Repository: virus-warnning/twnews Branch: develop Commit: 4c7ef4360184 Files: 64 Total size: 470.9 KB Directory structure: gitextract_2u5gsm6r/ ├── .github/ │ └── ISSUE_TEMPLATE/ │ ├── bug_report.md │ ├── feature_request.md │ ├── improvement.md │ └── magic.md ├── .gitignore ├── .pylintrc ├── LICENSE ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── README.rst ├── bin/ │ ├── busm_failed.py │ ├── fin_schedule.py │ ├── getnews.sh │ ├── publish.py │ └── weekly.py ├── docs/ │ ├── SOUP_NOTES.md │ └── changelog.md ├── postman/ │ ├── TWMKT.postman_collection.json │ └── TWMKT.postman_environment.json ├── requirements.txt ├── setup.py └── twnews/ ├── __init__.py ├── __main__.py ├── cache.py ├── common.py ├── conf/ │ ├── logging.yaml │ ├── news-soup.json │ └── usage.txt ├── exceptions.py ├── finance/ │ ├── __init__.py │ ├── broker.py │ ├── tdcc.py │ ├── ticksmap.py │ ├── tpex.py │ └── twse.py ├── res/ │ ├── ticksmap-captcha.xrc │ ├── ticksmap-locations.geojson │ └── ticksmap-template.html ├── samples/ │ ├── appledaily.html.xz │ ├── chinatimes.html.xz │ ├── cna.html.xz │ ├── ettoday.html.xz │ ├── ltn.html.xz │ ├── setn.html.xz │ └── udn.html.xz ├── search.py ├── soup.py └── tests/ ├── __init__.py ├── search/ │ ├── __init__.py │ ├── test_search_appledaily.py │ ├── test_search_cna.py │ ├── test_search_ettoday.py │ ├── test_search_ltn.py │ ├── test_search_setn.py │ └── test_search_udn.py └── soup/ ├── __init__.py ├── test_soup_appledaily.py ├── test_soup_chinatimes.py ├── test_soup_cna.py ├── test_soup_common.py ├── test_soup_ettoday.py ├── test_soup_ltn.py ├── test_soup_setn.py └── test_soup_udn.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: 回報錯誤 title: 摘要一下問題吧 labels: bug assignees: virus-warnning --- **問題描述** 盡可能清楚地描述狀況,讓我觀落陰不會走火入魔 **重現方法** 用下列步驟可以讓程式爆掉 1. python3 -m twnews ... 2. ... **預期行為** 我本來覺得應該會這樣 ... **實際行為** 結果變成這樣 ... ```bash $ python3 -m twnews soup --------------------------------------------------------------------------- 路徑: https://tw.news.appledaily.com/local/realtime/20181025/1453825 頻道: appledaily 標題: 男子疑久病厭世 學校圍牆上吊輕生亡 日期: 2018-10-25 12:03:00 記者: None 內文: 台北市北投區西安街二段 ``` **系統環境** - Python: [至少要 3.5 以上喔] - OS: [例如 Ubuntu 18.04] ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: 許個願望 title: 想要一個神奇的功能 labels: enhancement assignees: virus-warnning --- **許願動機** 描述一下這個願望能滿足什麼需求,或是對大家有什麼貢獻,現有功能無法滿足的原因等 **具體用法** 描述一下這個願望想做成什麼樣的形式,例如 function 定義,或是 command 用法 ================================================ FILE: .github/ISSUE_TEMPLATE/improvement.md ================================================ --- name: Improvement about: 現有功能改善 title: OOO效能改善 labels: improvement assignees: virus-warnning --- **問題摘要** 描述一下現有功能的問題,例如效能不佳,誤判率太高 **改善方式** 例如調整 SQL 語法,調整 Regex Pattern,或是改用OO演算法等 ================================================ FILE: .github/ISSUE_TEMPLATE/magic.md ================================================ --- name: Magic about: 變個魔法 (不提供訪客使用) title: 變個魔法 labels: magic assignees: virus-warnning --- **咒語內容** 希望機器人可以自己發現八卦,然後自動告訴主人 **施法細節** * [ ] 首先要 OOO * [ ] 然後要 XXX ================================================ FILE: .gitignore ================================================ # Python 3 *.pyc __pycache__ # Testing report .coverage # setup.py dist build twnews.egg-info # virtualenv sandbox # vim *.swp # MacOS .DS_Store ================================================ FILE: .pylintrc ================================================ [MASTER] # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. extension-pkg-whitelist= # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS # Add files or directories matching the regex patterns to the blacklist. The # regex matches against base names, not paths. ignore-patterns= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the # number of processors available to use. jobs=1 # Control the amount of potential inferred values when inferring a single # object. This can help the performance when dealing with large functions or # complex, nested conditions. limit-inference-results=100 # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= # Pickle collected data for later comparisons. persistent=yes # Specify a configuration file. #rcfile= # When enabled, pylint would attempt to guess common misconfiguration and emit # user-friendly hints instead of false-positive error messages. suggestion-mode=yes # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no [MESSAGES CONTROL] # Only show warnings with the listed confidence levels. Leave empty to show # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. confidence= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once). You can also use "--disable=all" to # disable everything first and then reenable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use "--disable=all --enable=classes # --disable=W". disable=print-statement, parameter-unpacking, unpacking-in-except, old-raise-syntax, backtick, long-suffix, old-ne-operator, old-octal-literal, import-star-module-level, non-ascii-bytes-literal, raw-checker-failed, bad-inline-option, locally-disabled, file-ignored, suppressed-message, useless-suppression, deprecated-pragma, use-symbolic-message-instead, apply-builtin, basestring-builtin, buffer-builtin, cmp-builtin, coerce-builtin, execfile-builtin, file-builtin, long-builtin, raw_input-builtin, reduce-builtin, standarderror-builtin, unicode-builtin, xrange-builtin, coerce-method, delslice-method, getslice-method, setslice-method, no-absolute-import, old-division, dict-iter-method, dict-view-method, next-method-called, metaclass-assignment, indexing-exception, raising-string, reload-builtin, oct-method, hex-method, nonzero-method, cmp-method, input-builtin, round-builtin, intern-builtin, unichr-builtin, map-builtin-not-iterating, zip-builtin-not-iterating, range-builtin-not-iterating, filter-builtin-not-iterating, using-cmp-argument, eq-without-hash, div-method, idiv-method, rdiv-method, exception-message-attribute, invalid-str-codec, sys-max-int, bad-python3-import, deprecated-string-function, deprecated-str-translate-call, deprecated-itertools-function, deprecated-types-field, next-method-defined, dict-items-not-iterating, dict-keys-not-iterating, dict-values-not-iterating, deprecated-operator-function, deprecated-urllib-function, xreadlines-attribute, deprecated-sys-function, exception-escape, comprehension-escape, duplicate-code, fixme # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). See also the "--disable" option for examples. enable=c-extension-no-member [REPORTS] # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details. #msg-template= # Set the output format. Available formats are text, parseable, colorized, json # and msvs (visual studio). You can also give a reporter class, e.g. # mypackage.mymodule.MyReporterClass. output-format=text # Tells whether to display a full report or only the messages. reports=no # Activate the evaluation score. score=yes [REFACTORING] # Maximum number of nested blocks for function / method body max-nested-blocks=5 # Complete name of functions that never returns. When checking for # inconsistent-return-statements if a never returning function is called then # it will be considered as an explicit return statement and no message will be # printed. never-returning-functions=sys.exit [LOGGING] # Format style used to check logging format string. `old` means using % # formatting, while `new` is for `{}` formatting. logging-format-style=old # Logging modules to check that the string format arguments are in logging # function parameter format. logging-modules=logging [SPELLING] # Limits count of emitted suggestions for spelling mistakes. max-spelling-suggestions=4 # Spelling dictionary name. Available dictionaries: none. To make it working # install python-enchant package.. spelling-dict= # List of comma separated words that should not be checked. spelling-ignore-words= # A path to a file that contains private dictionary; one word per line. spelling-private-dict-file= # Tells whether to store unknown words to indicated private dictionary in # --spelling-private-dict-file option instead of raising a message. spelling-store-unknown-words=no [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME, XXX, TODO [TYPECHECK] # List of decorators that produce context managers, such as # contextlib.contextmanager. Add to this list to register other decorators that # produce valid context managers. contextmanager-decorators=contextlib.contextmanager # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. generated-members= # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # Tells whether to warn about missing members when the owner of the attribute # is inferred to be None. ignore-none=yes # This flag controls whether pylint should warn about no-member and similar # checks whenever an opaque object is returned when inferring. The inference # can return multiple potential results while evaluating a Python object, but # some branches might not be evaluated, which results in partial inference. In # that case, it might be useful to still emit no-member and other checks for # the rest of the inferred objects. ignore-on-opaque-inference=yes # List of class names for which member attributes should not be checked (useful # for classes with dynamically set attributes). This supports the use of # qualified names. ignored-classes=optparse.Values,thread._local,_thread._local # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis. It # supports qualified module names, as well as Unix pattern matching. ignored-modules= # Show a hint with possible names when a member name was not found. The aspect # of finding the hint is based on edit distance. missing-member-hint=yes # The minimum edit distance a name should have in order to be considered a # similar match for a missing member name. missing-member-hint-distance=1 # The total number of similar names that should be taken in consideration when # showing a hint for a missing member. missing-member-max-choices=1 [VARIABLES] # List of additional names supposed to be defined in builtins. Remember that # you should avoid defining new builtins when possible. additional-builtins= # Tells whether unused global variables should be treated as a violation. allow-global-unused-variables=yes # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_, _cb # A regular expression matching the name of dummy variables (i.e. expected to # not be used). dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ # Argument names that match this expression will be ignored. Default to name # with leading underscore. ignored-argument-names=_.*|^ignored_|^unused_ # Tells whether we should check for unused import in __init__ files. init-import=no # List of qualified module names which can have objects that can redefine # builtins. redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io [FORMAT] # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format= # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' # Maximum number of characters on a single line. max-line-length=100 # Maximum number of lines in a module. max-module-lines=1000 # List of optional constructs for which whitespace checking is disabled. `dict- # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. # `trailing-comma` allows a space between comma and closing bracket: (a, ). # `empty-line` allows space-only lines. no-space-check=trailing-comma, dict-separator # Allow the body of a class to be on the same line as the declaration if body # contains single statement. single-line-class-stmt=no # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no [SIMILARITIES] # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no # Minimum lines number of a similarity. min-similarity-lines=4 [BASIC] # Naming style matching correct argument names. argument-naming-style=snake_case # Regular expression matching correct argument names. Overrides argument- # naming-style. #argument-rgx= # Naming style matching correct attribute names. attr-naming-style=snake_case # Regular expression matching correct attribute names. Overrides attr-naming- # style. #attr-rgx= # Bad variable names which should always be refused, separated by a comma. bad-names=foo, bar, baz, toto, tutu, tata # Naming style matching correct class attribute names. class-attribute-naming-style=any # Regular expression matching correct class attribute names. Overrides class- # attribute-naming-style. #class-attribute-rgx= # Naming style matching correct class names. class-naming-style=PascalCase # Regular expression matching correct class names. Overrides class-naming- # style. #class-rgx= # Naming style matching correct constant names. const-naming-style=UPPER_CASE # Regular expression matching correct constant names. Overrides const-naming- # style. #const-rgx= # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 # Naming style matching correct function names. function-naming-style=snake_case # Regular expression matching correct function names. Overrides function- # naming-style. #function-rgx= # Good variable names which should always be accepted, separated by a comma. good-names=i, j, k, ex, Run, _ # Include a hint for the correct naming format with invalid-name. include-naming-hint=no # Naming style matching correct inline iteration names. inlinevar-naming-style=any # Regular expression matching correct inline iteration names. Overrides # inlinevar-naming-style. #inlinevar-rgx= # Naming style matching correct method names. method-naming-style=snake_case # Regular expression matching correct method names. Overrides method-naming- # style. #method-rgx= # Naming style matching correct module names. module-naming-style=snake_case # Regular expression matching correct module names. Overrides module-naming- # style. #module-rgx= # Colon-delimited sets of names that determine each other's naming style when # the name regexes allow several styles. name-group= # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=^_ # List of decorators that produce properties, such as abc.abstractproperty. Add # to this list to register other decorators that produce valid properties. # These decorators are taken in consideration only for invalid-name. property-classes=abc.abstractproperty # Naming style matching correct variable names. variable-naming-style=snake_case # Regular expression matching correct variable names. Overrides variable- # naming-style. #variable-rgx= [STRING] # This flag controls whether the implicit-str-concat-in-sequence should # generate a warning on implicit string concatenation in sequences defined over # several lines. check-str-concat-over-line-jumps=no [IMPORTS] # Allow wildcard imports from modules that define __all__. allow-wildcard-with-all=no # Analyse import fallback blocks. This can be used to support both Python 2 and # 3 compatible code, which means that the block might have code that exists # only in one or another interpreter, leading to false positives when analysed. analyse-fallback-blocks=no # Deprecated modules which should not be used, separated by a comma. deprecated-modules=optparse,tkinter.tix # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled). ext-import-graph= # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled). import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled). int-import-graph= # Force import order to recognize a module as part of the standard # compatibility libraries. known-standard-library= # Force import order to recognize a module as part of a third party library. known-third-party=enchant [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__, __new__, setUp # List of member names, which should be excluded from the protected access # warning. exclude-protected=_asdict, _fields, _replace, _source, _make # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=cls [DESIGN] # Maximum number of arguments for function / method. max-args=5 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Maximum number of boolean expressions in an if statement. max-bool-expr=5 # Maximum number of branch for function / method body. max-branches=12 # Maximum number of locals for function / method body. max-locals=15 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of public methods for a class (see R0904). max-public-methods=20 # Maximum number of return / yield for function / method body. max-returns=6 # Maximum number of statements in function / method body. max-statements=50 # Minimum number of public methods for a class (see R0903). min-public-methods=2 [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "BaseException, Exception". overgeneral-exceptions=BaseException, Exception ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2018 Raymond Wu (小璋丸) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: PULL_REQUEST_TEMPLATE.md ================================================ **目的與用途** 描述一下這個 PR 的目的與用途 **被刪除的功能** 如果有刪除某些功能,請說明刪除原因以及效益 **被刪除的測試程式** 如果有刪除測試程式,請說明為何不再需要測試,以及對應的替代方案 ================================================ FILE: README.md ================================================ 台灣新聞拆拆樂的用來蒐集或處理大眾感興趣的資訊,目前著重在新聞和市場情報,希望能藉由這個工具讓其他人變出各種好玩的衍生應用,目前提供這些功能: * 將新聞網頁拆出標題,內文,報導時間,記者 * 關鍵字查新聞,並且可接續拆新聞或新聞數 * 蒐集三大法人,信用交易,借券賣出,股權分散表等市場資訊 ## 為什麼做這個? 最早的開發動機,是希望能做個工具能快速找到最新的凶宅,用來輔助我的另一個專案[鄉民風水師](https://geomancer.tacosync.com/),實現資料自動更新,所以做了拆站工具和搜尋爬蟲。做了一段時間也開始有話題性,就修了一些大家反應的問題。然後希望維護這專案的負擔不要太重,又寫了一些能發財的東西,然後就變成現在的樣子。如果想了解更多以前的事,可以參考[版本異動紀錄](docs/changelog.md)。 如果你是來找發財工具,另一個乏人問津的專案[群益證券聽牌機](https://github.com/virus-warnning/skcom)也歡迎來關注一下。 ## 怎麼用? **系統需求** * OS: 不限 * Python: 3.5 ~ 3.7 **安裝** ```sh # Windows (只有 Python 3.x 的環境) pip install twnews # macOS, Linux (Python 2.x 與 3.x 並存的環境) pip3 install twnews ``` **體驗** 為了方便有緣人使用,開發了一些 console 工具讓人可以不用寫程式就立即體驗 例如朝聖一則凶宅新聞: ```bash python3 -m twnews soup https://www.setn.com/News.aspx?NewsID=490688&From=Search&Key=%E5%8F%B0%E4%B8%AD%E6%9C%80%E7%8C%9B%E5%85%87%E5%AE%85%EF%BC%81%E9%80%A36%E5%90%8D%E6%88%BF%E5%AE%A2%E5%90%8C%E4%BD%8D%E7%BD%AE%E4%B8%8A%E5%90%8A --------------------------------------------------------------------------- 原始路徑: https://www.setn.com/News.aspx?NewsID=490688 最終路徑: https://www.setn.com/m/news.aspx?newsid=490688 頻道: setn 標題: 堪稱台中最猛兇宅!連續6名房客上吊 竟都死在相同位置 日期: 2019-02-07 20:00:00 記者: 林盈君 內文: 記者林盈君/台中報導許多人不論是租屋、購屋,都擔心會碰上兇宅,有位職業為房仲的網友,就在PTT上,分享他曾經遇過的詭異事件! 他說約在幾年前,接到一個同行介紹的案子,是一間位於台中沙鹿的頂樓老公寓,當時他看到房屋價格時,簡直低到讓他不敢相信,詢問過 屋主之後,屋主表示屋內曾有人上吊死亡,而且是「連續6名房客」,且竟然都在「同一位置」選擇輕生!▲該公寓曾發生6名租客上吊事件 。(圖/示意圖/翻攝pixabay)據悉,幾年前曾有一名房客,在屋內上吊自殺,屋主之後請了法師來超渡誦經,就低價再次租給其他房客 ,不料6個月後,該房客卻遲遲沒有交租金,就連簡訊電話都無回應,他只好請警察協助開門,沒想到進到屋內就發現,房客已經上吊死亡 ,而且死亡的位置,跟第一個房客上吊的地方「一模一樣」,實在令人毛骨悚然。▲許多人認為這根本是「抓交替」。(圖/示意圖/翻攝 pixabay)在那之後,屋主連續租給其他幾位房客,但卻頻頻發生意外,6位租客全都選擇在屋內上吊自殺,上吊的位置也全部一模一樣, 這樣詭異的情況,也讓轄區員警懷疑,屋主是不是殺害租客後,用上吊來掩蓋罪行,讓屋主相當崩潰!屋主曾無奈表示「1、2個就算了,是 連續6個租客你知道嗎?」、「這6個租客我根本不知道為什麼他們最後都上吊死了,而且上吊的位置全都一模一樣」。更加詭異的是,連續 6名房客上吊身亡後,屋主有2年多都沒再把房子出租,屋內空無一人,但對面鄰居卻跟他表示,看到有人進出他的房子,樓下的住戶也說, 上面常常傳來很用力踩地板、拖著椅子及摔東西的聲音,甚至連一樓的住戶,都說看到房子的陽台上有人,但等到屋主拿鑰匙進屋查看時, 發現從門口到陽台都是厚厚的灰塵,完全沒有任何人走動的跡象。因為發生過命案,再加上接連詭異的情況,讓對面鄰居和樓下住戶都陸續 搬走,也有房仲找投資客來看房,但大家都覺得這房子太邪門,認為根本是「抓交替」。後來有位投資客表示意願想買,但到簽約當天屋主 卻反悔,表示不想讓對方成為上吊身亡的「第七個人」,所以直到現在,那間房子依然空在那裡,也沒有其他房客入住。 ★ 三立新聞網提醒您:勇敢求救並非弱者,生命一定可以找到出路。透過守門123步驟-1問2應3轉介,你我都可以成為自殺防治守門人。 ※ 安心專線:0800-788-995(0800-請幫幫-救救我) ※ 張老師專線:1980 ※ 生命線專線:1995 ※ 反霸凌專線:0800-200-885 有效內容率: 2.16% --------------------------------------------------------------------------- ``` ## 深入了解 * [新聞 Console 工具](https://github.com/virus-warnning/twnews/wiki/01.%E6%96%B0%E8%81%9E-Console-%E5%B7%A5%E5%85%B7) * [新聞 API](https://github.com/virus-warnning/twnews/wiki/02.%E6%96%B0%E8%81%9E-API) * [股市情報蒐集工具](https://github.com/virus-warnning/twnews/wiki/03.%E8%82%A1%E5%B8%82%E6%83%85%E5%A0%B1%E8%92%90%E9%9B%86%E5%B7%A5%E5%85%B7) ================================================ FILE: README.rst ================================================ 台灣新聞拆拆樂 (twnews) 用來分解台灣各大新聞網站,取出重要的純文字內容 功能 ==== - 支援蘋果日報、中時電子報、中央社、東森新聞雲、自由時報、三立新聞網、聯合新聞網 - 使用行動版網頁與快取機制節省流量 - 盡可能找出記者姓名 - 利用 BeautifulSoup 的 CSS selector 功能搭配設定檔分解,容易同步網站改版 - 解決 Python for Windows CP950 編碼問題,節省處理鳥事的時間 - 每週執行自動化測試檢查分解程式的時效性 0.3.2 新功能 - 更新東森新聞爬蟲設定 - 解決自由地產、自由時尚因 lxml 版本太舊而拆失敗的問題 - 新增證交所資料蒐集程式 (三大法人、信用交易、借券賣出、鉅額交易、ETF淨值溢價率) - 改善集保中心資料蒐集程式 (股權分散表) 0.3.1 新功能 - 跟進中時電子報的排版變更 - 支援蘋果地產 - 股權分散表資料表結構改善 - 股權分散表資料表日期改為 ISO 格式 0.3.0 新功能 - 股權分散表 CSV 檔蒐集程式 - 修正自由時報娛樂新聞分解問題 `#50 `_ (回報者: `CpOuyang `_) 0.2.4 新功能 - 改善記者姓名辨識能力 - 自由時報分類新聞自動切換手機版 - 修正自由時報部分新聞無法取得日期問題 - 修正中國時報部分新聞無法取得記者問題 - 修正蘋果日報搜尋功能自動翻頁問題 - 增加測試項目 安裝 ==== .. code:: bash pip3 install twnews 工具程式 ======== .. code:: bash # 拆新聞 python3 -m twnews soup https://tw.news.appledaily.com/local/realtime/20181025/1453825 # 搜尋 python3 -m twnews search 韓國瑜 udn # 搜尋 + 拆 python3 -m twnews snsp 酒駕 # 統計關鍵字出現在標題的次數 python3 -m twnews cpkw 柯文哲 # 查看用法 python3 -m twnews help 範例 - 分解新聞 =============== .. code:: python from twnews.soup import NewsSoup nsoup = NewsSoup('https://tw.news.appledaily.com/local/realtime/20181025/1453825') print('頻道: {}'.format(nsoup.channel)) print('標題: {}'.format(nsoup.title())) print('日期: {}'.format(nsoup.date())) print('記者: {}'.format(nsoup.author())) print('內文:') print(nsoup.contents()) print('有效內容率: {:.2f}%'.format(nsoup.effective_text_rate() * 100)) .. code:: text 頻道: appledaily 標題: 男子疑久病厭世 學校圍牆上吊輕生亡│即時新聞│20181025│蘋果日報 日期: 2018-10-25 12:03:00 記者: 江宏倫 內文: 台北市北投區西安街二段,昨晚10時許,1名游姓男子(約80歲)坐在學校圍牆邊上吊輕生,路過民眾驚見嚇得趕緊報案,警消趕抵,時發現輕生男子已經沒有生命跡象,緊急送醫搶救仍宣告不治,警方初步調查排除外力介入,輕生原因仍有待釐清。 警消表示,抵達現場時,發現游男坐在某國中圍牆邊上吊輕生,立即將他救下,但已無呼吸心跳,立即進行CPR並送醫搶救,家屬接獲通知趕抵醫院,同意放棄急救。警方調查,年約80多歲的游男,疑似因長期洗腎又患有心臟疾病、糖尿病才會想不開,現場並無打鬥痕跡,初步已排除外力介入,詳細輕生原因仍待調查釐清。(突發中心江宏倫/台北報導)《蘋果》關心你自殺解決不了問題,卻留給家人無比悲痛。請珍惜生命。再給自己一次機會自殺防治諮詢安心專線:0800-788995(24小時) 生命線協談專線:1995 張老師專線:1980出版時間02:07更新時間12:03 >>加入蘋果日報粉絲團94即時94狂! 有效內容率: 1.37% 範例 - 關鍵字搜尋 + 分解新聞 ============================ .. code:: python from twnews.search import NewsSearch nsearch = NewsSearch( 'ltn', limit=10, beg_date='2018-08-03', # 自由時報的日期範圍只能在 90 天以內 end_date='2018-11-01' ) nsoups = nsearch.by_keyword('上吊', title_only=True).to_soup_list() for (i, nsoup) in enumerate(nsoups): print('{:03d}: {}'.format(i, nsoup.path)) if nsoup.title() is not None: print(' 記者: {} / 日期: {}'.format(nsoup.author(), nsoup.date())) print(' 標題: {}'.format(nsoup.title())) print(' {} ...'.format(nsoup.contents()[0:30])) else: print(' 新聞分解失敗,無法識別 DOM 結構') .. code:: text 000: http://m.ltn.com.tw/news/society/breakingnews/2581807 記者: None / 日期: 2018-10-15 23:51:00 標題: 疑因病厭世 男子國小圖書館上吊身亡 〔即時新聞/綜合報導〕台北市萬華區的老松國小今(15)日早上 ... 001: http://m.ltn.com.tw/news/society/breakingnews/2579780 記者: None / 日期: 2018-10-13 16:52:00 標題: 汐止五指山驚傳男子上吊 水管繞頸陳屍樹林 〔記者林嘉東、吳昇儒/新北報導〕台北市郭姓男子今天午後被發現 ... 002: http://m.ltn.com.tw/news/entertainment/breakingnews/2579590 新聞分解失敗,無法識別 DOM 結構 003: http://m.ltn.com.tw/news/society/breakingnews/2577987 記者: 謝武雄 / 日期: 2018-10-11 18:10:00 標題: 議員尿急樹林解放赫見白骨 男子上吊這天正好滿七... [記者謝武雄/桃園報導]桃園市大園選區市議員游吾和昨天在臉書 ... 004: http://m.ltn.com.tw/news/entertainment/breakingnews/2577596 新聞分解失敗,無法識別 DOM 結構 005: http://m.ltn.com.tw/news/society/breakingnews/2570595 記者: 吳仁捷 / 日期: 2018-10-04 13:40:00 標題: 疑借貸千萬翻身失敗 公墓上吊嚇壞爬山男 〔記者吳仁捷/新北報導〕章姓男子今天上午到新北市樹林大同山區 ... 006: http://m.ltn.com.tw/news/entertainment/breakingnews/2567740 新聞分解失敗,無法識別 DOM 結構 007: http://m.ltn.com.tw/news/life/breakingnews/2567637 記者: None / 日期: 2018-10-01 23:35:00 標題: 「肉粽」難送! 員林三合院連5人在「同條樑」上吊 〔即時新聞/綜合報導〕在彰化沿海一帶,為上吊身亡者「送肉棕」 ... 008: http://m.ltn.com.tw/news/society/breakingnews/2561962 記者: None / 日期: 2018-09-26 11:08:00 標題: 男子北美館樹林上吊亡 警到場調查 〔即時新聞/綜合報導〕今天上午10時許,台北市立美術館停車場 ... 009: http://m.ltn.com.tw/news/society/breakingnews/2561566 記者: 黃良傑 / 日期: 2018-09-25 18:05:00 標題: 美籍女師上吊租屋處身亡 美籍男友:房內發現遺書 〔記者黃良傑/高雄報導〕一名美籍女老師今午被男友發現陳屍租屋 ... ================================================ FILE: bin/busm_failed.py ================================================ import os import sys import threading sys.path.append(os.path.realpath('.')) import twnews.common as cm # 這一行搭配 logger.error() 可以讓程式在 Mac 環境爆掉 # objc[70893]: +[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called. # objc[70893]: +[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug. # 但目前找不到具體原因 import twnews.finance.twse as twse def main(): if os.fork() > 0: exit(0) logger = cm.get_logger('finance') logger.error('test') if __name__ == '__main__': main() ================================================ FILE: bin/fin_schedule.py ================================================ import logging import os import schedule import signal import sys import threading import time from datetime import datetime, timedelta sys.path.append(os.path.realpath('.')) import twnews.common as cm import twnews.finance.twse as twse import twnews.finance.tpex as tpex import twnews.finance.tdcc as tdcc class JustDaemon: """ 定型化 Daemon TODO: 分割成獨立套件 """ def __init__(self, init_task=None, loop_task=None, stdout='/dev/null', stderr='/dev/null', background=True): if background and os.fork() > 0: exit(0) self.init_task = init_task if init_task is not None else self.do_nothing self.loop_task = loop_task if loop_task is not None else self.do_nothing self.stdout = stdout self.stderr = stderr self.background = background self.close_requested = False def do_nothing(self): pass def on_quit(self, signum, frame): self.close_requested = True def listen_sys_signals(self): ACCEPTED_SIGNALS = [ signal.SIGHUP, # 1 signal.SIGINT, # 2 signal.SIGQUIT, # 3 signal.SIGABRT, # 6 signal.SIGTERM # 15 ] for sig in ACCEPTED_SIGNALS: signal.signal(sig, self.on_quit) def stream_redirect(self): if self.background: outpath = os.path.expanduser(self.stdout) sys.stdout = open(outpath, 'w') errpath = os.path.expanduser(self.stderr) sys.stderr = open(errpath, 'w') def stream_flush(self): if self.background: sys.stdout.flush() sys.stderr.flush() def stream_close(self): if self.background: sys.stdout.close() sys.stderr.close() def pidfile_create(self): # 產生 pid file self.pid_file = os.path.expanduser('~/.twnews/fin_schedule.pid') pid_base = os.path.dirname(self.pid_file) if not os.path.isdir(pid_base): os.makedirs(pid_base) with open(self.pid_file, 'w') as pid_stream: pid_stream.write('%s' % os.getpid()) def pidfile_remove(self): # 移除 pid file os.remove(self.pid_file) def run(self): self.listen_sys_signals() self.stream_redirect() self.pidfile_create() attrs = {} self.init_task(attrs) while not self.close_requested: self.loop_task(attrs) self.stream_flush() # Make the next waking near 0 second. t = time.time() delay = 1 - (t - int(t)) time.sleep(delay) self.pidfile_remove() self.stream_close() class ScheduleDaemon(JustDaemon): """ 排程型 Daemon TODO: 分割成獨立套件 """ def __init__(self, schedule_table, stdout='/dev/null', stderr='/dev/null', background=True): self.schedule_table = schedule_table super().__init__( init_task = self.init_task, loop_task = self.loop_task, stdout = stdout, stderr = stderr, background = background ) def init_task(self, attrs): for run_at in self.schedule_table: func = self.schedule_table[run_at]['func'] args = self.schedule_table[run_at]['args'] weekend = True if 'weekend' in self.schedule_table[run_at]: weekend = self.schedule_table[run_at]['weekend'] if weekend: schedule.every().day.at(run_at).do(self.run_parallel, func, args) else: schedule.every().monday.at(run_at).do(self.run_parallel, func, args) schedule.every().tuesday.at(run_at).do(self.run_parallel, func, args) schedule.every().wednesday.at(run_at).do(self.run_parallel, func, args) schedule.every().thursday.at(run_at).do(self.run_parallel, func, args) schedule.every().friday.at(run_at).do(self.run_parallel, func, args) def loop_task(self, attrs): schedule.run_pending() def run_parallel(self, func, args): th = threading.Thread(target=func, args=args) th.start() def im_fine(): logger = cm.get_logger('finance') logger.info('I\'m fine. (%s)', __file__) def tpe_at(timestr): hh_adjust = (time.altzone / -3600) - 8 hh = (int(timestr[0:2]) + hh_adjust) % 24 mm = int(timestr[3:5]) return '%02d:%02d' % (hh, mm) def main(): # 注意!! args 要用 list 不可以用 tuple,否則傳遞一個字串時,會把每個字元當成一個參數傳遞 ScheduleDaemon( schedule_table = { # 每日健康回報 tpe_at('09:30'): { 'func': im_fine, 'args': [] }, tpe_at('14:00'): { 'func': im_fine, 'args': [] }, # 證交所 tpe_at('14:09'): { 'func': twse.sync_dataset, 'args': ['borrowed'], 'weekend': False }, tpe_at('15:57'): { 'func': twse.sync_dataset, 'args': ['etfnet'], 'weekend': False }, tpe_at('16:44'): { 'func': twse.sync_dataset, 'args': ['institution'], 'weekend': False }, tpe_at('17:33'): { 'func': twse.sync_dataset, 'args': ['block'], 'weekend': False }, tpe_at('21:41'): { 'func': twse.sync_dataset, 'args': ['margin'], 'weekend': False }, tpe_at('21:42'): { 'func': twse.sync_dataset, 'args': ['selled'], 'weekend': False }, # 櫃買中心 tpe_at('16:49'): { 'func': tpex.sync_dataset, 'args': ['institution'], 'weekend': False }, tpe_at('17:48'): { 'func': tpex.sync_dataset, 'args': ['block'], 'weekend': False }, tpe_at('21:47'): { 'func': tpex.sync_dataset, 'args': ['margin'], 'weekend': False }, tpe_at('21:48'): { 'func': tpex.sync_dataset, 'args': ['selled'], 'weekend': False }, # 集保中心 tpe_at('07:01'): { 'func': tdcc.sync_dataset, 'args': [] }, }, # background = False ).run() if __name__ == '__main__': main() ================================================ FILE: bin/getnews.sh ================================================ # 製作新聞離線範本 SAMPLE_DIR='twnews/samples' USER_AGENT='Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36' wget -U "$USER_AGENT" -O $SAMPLE_DIR/appledaily.html https://tw.news.appledaily.com/local/realtime/20160521/867195 wget -U "$USER_AGENT" -O $SAMPLE_DIR/chinatimes.html https://www.chinatimes.com/realtimenews/20180916001767-260402 wget -U "$USER_AGENT" -O $SAMPLE_DIR/cna.html https://www.cna.com.tw/news/asoc/201603190029-1.aspx wget -U "$USER_AGENT" -O $SAMPLE_DIR/ettoday.html https://www.ettoday.net/news/20171209/1069025.htm wget -U "$USER_AGENT" -O $SAMPLE_DIR/ltn.html https://m.ltn.com.tw/news/life/breakingnews/2504351 wget -U "$USER_AGENT" -O $SAMPLE_DIR/setn.html https://www.setn.com/m/News.aspx?NewsID=350370 wget -U "$USER_AGENT" -O $SAMPLE_DIR/udn.html https://udn.com/news/story/7315/3705102 # $WGET -O $SAMPLE_DIR/judicial-cp950.html http://aomp.judicial.gov.tw/abbs/wkw/WHD2ASHOW.jsp?rowid=%2Fsld%2F10703%2F09162840289.020 # iconv -f cp950 -t utf8 $SAMPLE_DIR/judicial-cp950.html > $SAMPLE_DIR/judicial.html # rm -f $SAMPLE_DIR/judicial-cp950.html xz -f $SAMPLE_DIR/*.html ================================================ FILE: bin/publish.py ================================================ #!/usr/bin/env python3 # # 必要工具套件: # * pylint # * rstcheck # * setuptools import configparser import os import re import subprocess import sys def get_wheel(): """ 製作 wheel 檔案與取得檔名 """ comp = subprocess.run(['python3', 'setup.py', 'bdist_wheel'], capture_output=True) if comp.returncode != 0: return False wheel = False stdout = comp.stdout.decode('utf-8').split('\n') for line in stdout: match = re.search('dist/twnews-.+\.whl', line) if match is not None: wheel = match.group(0) break return wheel def get_latest_python(): """ 選擇 pyenv 環境中 3.5 ~ 3.8 的最新版本 """ detected_ver = { '3.5': -1, '3.6': -1, '3.7': -1, '3.8': -1 } comp = subprocess.run(['pyenv', 'versions'], capture_output=True) stdout = comp.stdout.decode('utf-8').strip().split('\n') for line in stdout: match = re.match(' (\d\.\d)\.(\d+)', line) if match is not None: minor_ver = match.group(1) patch_ver = int(match.group(2)) if minor_ver in detected_ver and \ patch_ver > detected_ver[minor_ver]: detected_ver[minor_ver] = patch_ver latest_ver = [] for minor_ver in detected_ver: if detected_ver[minor_ver] > -1: full_ver = '%s.%d' % (minor_ver, detected_ver[minor_ver]) latest_ver.append(full_ver) return latest_ver def test_in_virtualenv(pyver, wheel): """ 配置 virtualenv 並執行測試程式 """ # 安裝 virtualenv src = os.path.expanduser('~/.pyenv/versions/%s/bin/python' % pyver) dst = 'sandbox/%s' % pyver comp = subprocess.run(['virtualenv', '-p', src, dst]) if comp.returncode != 0: return False # 測試 wheel 包 # 1. 安裝 wheel # 2. 安裝 green # 3. 執行測試程式 os.chdir(dst) wheel = '../../' + wheel comp = subprocess.run(['bin/pip', 'install', wheel, 'green']) if comp.returncode == 0: comp = subprocess.run(['bin/green', '-vv', 'twnews']) os.chdir('../..') return (comp.returncode == 0) def wheel_check(): """ 檢查 wheel 是否能正常運作在各個 Python 版本環境上 """ """ print('檢查 logging.ini') config = configparser.ConfigParser() config.read('twnews/conf/logging.ini') if config['handler_stdout']['level'] != 'CRITICAL': print('handler_stdout 忘記切換成 CRITICAL level') exit(1) """ print('檢查程式碼品質') ret = os.system('pylint -f colorized twnews') if ret != 0: print('檢查沒通過,停止封裝') exit(ret) print('檢查 README.rst') ret = os.system('rstcheck README.rst') if ret != 0: print('檢查沒通過,停止封裝') exit(ret) print('偵測可用的測試環境') os.system('rm -rf sandbox/*') wheel = get_wheel() latest_python = get_latest_python() if len(latest_python) == 0: print('沒有任何可用的測試環境') exit(1) for pyver in latest_python: print('測試 Python %s' % pyver) test_in_virtualenv(pyver, wheel) def upload_to_pypi(test=False): """ 上傳 wheel 到 PyPi """ # 檢查 ~/.pypirc 是否存在 if not os.path.isfile(os.path.expanduser('~/.pypirc')): print('缺少 pypi 設定檔 ~/.pypirc') print('參考: https://gist.github.com/ibrahim12/c6a296c1e8f409dbed2f') # 重新產生 wheel 與上傳前確認 wheel = get_wheel() prompt = '準備上傳的檔案是 %s, 確定上傳嗎 [y/n]? ' % wheel print(prompt, end='', flush=True) ans = sys.stdin.readline().strip() if ans != 'y': print('取消上傳') return # 上傳 wheel cmd = ['twine', 'upload'] if test: cmd.append('--repository') cmd.append('testpypi') cmd.append('--verbose') cmd.append(wheel) comp = subprocess.run(cmd) if comp.returncode == 0: print('上傳成功') else: print('上傳失敗') def main(): # 確保不在 repo 目錄也能正常執行 TWNEWS_HOME = os.path.realpath(os.path.dirname(__file__) + '/..') os.chdir(TWNEWS_HOME) action = 'wheel' if len(sys.argv) > 1: action = sys.argv[1] if action == 'release': upload_to_pypi() elif action == 'test': upload_to_pypi(True) elif action == 'wheel': wheel_check() else: print('Unknown action "%s".' % action) exit(1) if __name__ == '__main__': main() ================================================ FILE: bin/weekly.py ================================================ #!/usr/bin/env python3 import json import os import os.path import re import smtplib from email.header import Header from email.mime.text import MIMEText # 載入隱私設定 conf = None CONF_PATH = os.path.expanduser('~/.twnews/weekly.json') if os.path.isfile(CONF_PATH): with open(CONF_PATH, 'r') as conf_file: conf = json.load(conf_file) if conf is None: print('Cannot load "{}".'.format(CONF_PATH)) exit(1) # 測試 working_dir = os.path.realpath(os.path.dirname(__file__) + '/..') cmd = 'cd {} && python3 -m unittest discover -v 2>&1 1>/dev/null'.format(working_dir) pipe = os.popen(cmd, 'r') detail = pipe.read() ret = pipe.close() # 組信 if ret is None: subject = '[twnews] 每週測試 - 成功 ⭕️' contents = re.sub(r'\n\s+\| ', '\n', ''' |

每週測試成功

|

詳細內容:

|
        | {}
        | 
''', re.M).strip().format(detail) else: subject = '[twnews] 每週測試 - 失敗 ❌' contents = re.sub(r'\n\s+\| ', '\n', ''' |

每週測試失敗 ({})

|

詳細內容:

|
        | {}
        | 
''', re.M).strip().format(ret, detail) msg = MIMEText(contents, 'html', 'utf-8') msg['Subject'] = Header(subject) msg['From'] = '{} <{}>'.format(Header(conf['from_name']).encode(), conf['from_mail']) msg['To'] = '{} <{}>'.format(Header(conf['to_name']).encode(), conf['to_mail']) smtp_data = msg.as_string() # 發信 try: server = smtplib.SMTP(conf['smtp_host'], conf['smtp_port']) server.set_debuglevel(1) server.starttls() server.login(conf['smtp_user'], conf['smtp_pass']) server.sendmail(conf['from_mail'], conf['to_mail'], smtp_data) server.close() except Exception as ex: print('SMTP 異常:', ex) ================================================ FILE: docs/SOUP_NOTES.md ================================================ # 新聞網站技術細節 ### 新聞分解 頻道 | RWD | 轉址 | 記者欄 ---- | ---- | ---- | ---- 蘋果 | 半殘 | - | X 中時 | 完整 | - | O 中央社 | 完整 | - | X 東森新聞雲 | 半殘 | - | X 自由時報 | 無 | X | X 三立新聞網 | 無 | O | X 聯合新聞網 | 完整 | - | O * 中時幾乎都有註明記者 * 聯合記者欄可能不存在 * 三立偵測到網址與裝置類型不符會發出 HTTP 302 轉址,要關閉自動跟隨參數避免程式誤判 * 完整 RWD 表示行動版和桌面版使用同一個網址,且 DOM 結構差異不大 * 半殘 RWD 表示行動版和桌面版使用同一個網址,但 DOM 結構差異很大 * 無 RWD 表示行動版和桌面版不在同一個網址上 ### 新聞搜尋 頻道 | 介面 | 翻頁參數 | 日期範圍參數 ---- | ---- | ---- | ---- 蘋果 | 傳統網頁 | O | O 中時 | 沒提供 | - | - 中央社 | API | O | X 東森新聞雲 | 傳統網頁 | O | 特殊用法 自由時報 | 傳統網頁 | O | O 三立新聞網 | 傳統網頁 | O | X 聯合新聞網 | 傳統網頁 | O | X * 蘋果、自由,可以用同一個模式運作 * 三立、聯合、東森,可以用同一個模式運作 * 中央社有提供 JSON API,不用拆網頁,要獨立一個模式運作 * 自由的時間區間只能設定三個月內,應該是全文檢索引擎效能不足 * 東森新聞雲雖然有提供時間範圍 daydiff(1~3) 但是不好用,當作沒這參數吧 * 中時直接掛 Google 自訂搜尋,這部份有點瞎 自由時報聲明的查詢範圍是 3 個月,實測結果有些微差異,應該是相減需 ≤90 天 ``` # 2018-08-02 ~ 2018-11-01 沒有搜尋結果 nsearch = NewsSearch('ltn', '2018-08-02', '2018-11-01', 100) # 2018-08-03 ~ 2018-11-01 有搜尋結果 nsearch = NewsSearch('ltn', '2018-08-03', '2018-11-01', 100) ``` ### 新聞台搜尋效能比較 測試方法為下列指令連續跑 3 次,取單頁處理時間 ```bash python3 -m twnews sncp ```   | 1st | 2nd | 3rd ---- | ---- | ---- | ---- 蘋果日報 | 0.40 | 0.03 | 0.03 中央社 | 0.21 | 0.14 | 0.15 東森新聞雲 | 0.11 | 0.13 | 0.08 自由時報 | 0.79 | 0.02 | 0.02 三立新聞網 | 0.21 | 0.02 | 0.02 聯合新聞網 | 1.76 | 0.06 | 0.06 * 沒快取的狀況下最慢的依序是: 聯合 > 自由 > 蘋果 * 中央社和東森可能沒有快取機制,其餘都有查詢快取 * 三立的行動搜尋介面,頁籤沒有最後一頁的連結,只有桌面版有提供 ================================================ FILE: docs/changelog.md ================================================ ## 0.3.x 0.3 的開發主軸是財經資料蒐集,針對證交所,櫃買中心,集保中心,公開資訊觀測站等地方取得有價值資料,並且匯入到 SQLite 方便使用。 ### 0.3.3 * 櫃買中心三大法人,融資融券,鉅額交易 - #67 * 證交所爬蟲穩定性改善 - #69 * 集保中心爬蟲 Log Level 調整 - #73 * LZMA 壓縮快取檔 - #77 #78 #79 * 依新聞台名稱分配快取目錄 - #76 * 處理蘋果日報亂碼問題 - #80 #81 * 事務性工作 - #85 #74 #70 ### 0.3.2 * 爬證交所三大法人,信用交易,借券賣出,鉅額交易,ETF折溢價率 - #56 #68 * 股權分散表爬蟲重構 - #66 * 修正新聞爬蟲對自由天下與自由時尚的相容問題 - #61 * 修正蘋果日報內文無法取得問題 - #62 * 修正東森時尚日期格式問題 - #63 * 事務性工作 - #72 ### 0.3.1 * 股權分散表改用等級分表 - #57 * 股權分散表日期改用 ISO 格式 - #58 * 修正蘋果地產無法使用 https 問題 - #54 * 修正中時網頁結構改變問題 - #59 * 事務性工作 - #60 ### 0.3.0 * 爬股權分散表 - #51 * 解決 // 開頭網址無法正確處理的問題 - #50 (回報者: [CpOuyang](//github.com/CpOuyang)) * 東森測試程式增加 proxy 參數解決檔日本 linode 問題 - #52 * 事務性工作 - #55 ## 0.2.x 0.2 的開發主軸是新聞搜尋,針對各家新聞網站的搜尋功能,設計成行為一致的 API,簡化找新聞的需求,也解決拆新聞過程中發現的問題,列入測試樣本。 ### 0.2.5 * Issue Template - #46 ### 0.2.4 * 搜尋功能測試程式 - #37 * 增加 proxy 設計,讓東森新聞雲在日本 linode 也能使用 - #27 * 解決自由時報存在多種日期格式問題 - #34 * 強化記者姓名的辨識能力 - #40 * 被自動轉址時,自動切換分解新聞設定 - #43 * 修正蘋果日報搜尋的翻頁參數錯誤 - #44 * 事務性工作 - #45 ### 0.2.3 * 解決各家新聞的子頻道編排相容性問題 - #31 * 新聞爬蟲重構 - #39 * 程式碼導入 pylint 檢查,遵循 PEP8 規範 - #38 * 事務性工作 - #42 ### 0.2.2 * 修正 isinstance 用錯類別的問題 - #38 ### 0.2.1 * 新聞標題統計功能 - #33 * 蘋果日報搜尋改用 XHR - #30 * 事務性工作 - #32 ### 0.2.0 * 新聞關鍵字搜尋功能 - #9 # 0.1.x 0.1 的開發主軸是設計一個通用型的爬蟲,透過爬蟲設定值依照不同的新聞網站拆解 HTML 結構,取得標題,內文,記者,日期等資訊。 ### 0.1.10 * 解決 Python 3.7 for Windows 相容性問題 - #28 * 解決 Python 3.5 3.6 for Windows 相容性問題 - #29 ### 0.1.9 * 作者欄位加強測試 - #7 * 不理想 URL 測試 - #10 * 壓縮快取檔 - #15 * 壓縮範本檔 - #16 * 使用檔案儲存 log - #17 * 提供 URL 參數直接在 console 拆新聞 - #20 * 新聞爬蟲定期測試程式 - #24 * Python 3.5 相容設計 - #25 * 事務性工作 - #26 ### 0.1.8 * 爬蟲支援中時電子報 - #4 * 事務性工作 - #12 #13 #14 ### 0.1.7 * 清除快取前,先偵測目錄是否存在 - #2 * 變更快取目錄 - #5 * 移除 unicode_escape() - #6 * 計算有效內容率 - #8 * 變更頻果日報標題 CSS Selector - #11 * 事務性工作 - #3 ================================================ FILE: postman/TWMKT.postman_collection.json ================================================ { "info": { "_postman_id": "96e57888-4ea0-406b-9f9b-774e3cf3896f", "name": "0xFE-TWMKT", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item": [ { "name": "[證交] 00 三大法人", "request": { "method": "GET", "header": [], "url": { "raw": "http://www.twse.com.tw/fund/T86?response={{TWSE_EXFORMAT}}&date={{TWSE_EXDATE}}&selectType=ALL", "protocol": "http", "host": [ "www", "twse", "com", "tw" ], "path": [ "fund", "T86" ], "query": [ { "key": "response", "value": "{{TWSE_EXFORMAT}}" }, { "key": "date", "value": "{{TWSE_EXDATE}}" }, { "key": "selectType", "value": "ALL" } ] } }, "response": [] }, { "name": "[證交] 01 融資融券", "request": { "method": "GET", "header": [], "url": { "raw": "http://www.twse.com.tw/exchangeReport/MI_MARGN?response={{TWSE_EXFORMAT}}&date={{TWSE_EXDATE}}&selectType=ALL", "protocol": "http", "host": [ "www", "twse", "com", "tw" ], "path": [ "exchangeReport", "MI_MARGN" ], "query": [ { "key": "response", "value": "{{TWSE_EXFORMAT}}" }, { "key": "date", "value": "{{TWSE_EXDATE}}" }, { "key": "selectType", "value": "ALL" } ] } }, "response": [] }, { "name": "[證交] 02 鉅額交易", "request": { "method": "GET", "header": [], "url": { "raw": "http://www.twse.com.tw/block/BFIAUU?response={{TWSE_EXFORMAT}}&date={{TWSE_EXDATE}}&selectType=S", "protocol": "http", "host": [ "www", "twse", "com", "tw" ], "path": [ "block", "BFIAUU" ], "query": [ { "key": "response", "value": "{{TWSE_EXFORMAT}}" }, { "key": "date", "value": "{{TWSE_EXDATE}}" }, { "key": "selectType", "value": "S" } ] } }, "response": [] }, { "name": "[證交] 03 融券借券", "request": { "method": "GET", "header": [], "url": { "raw": "http://www.twse.com.tw/exchangeReport/TWT93U?response={{TWSE_EXFORMAT}}&date={{TWSE_EXDATE}}", "protocol": "http", "host": [ "www", "twse", "com", "tw" ], "path": [ "exchangeReport", "TWT93U" ], "query": [ { "key": "response", "value": "{{TWSE_EXFORMAT}}" }, { "key": "date", "value": "{{TWSE_EXDATE}}" } ] } }, "response": [] }, { "name": "[證交] 04 可借券賣出", "request": { "method": "GET", "header": [], "url": { "raw": "http://www.twse.com.tw/SBL/TWT96U?response=csv", "protocol": "http", "host": [ "www", "twse", "com", "tw" ], "path": [ "SBL", "TWT96U" ], "query": [ { "key": "response", "value": "csv" } ] } }, "response": [] }, { "name": "[證交] 05 ETF 折溢價", "request": { "method": "GET", "header": [], "url": { "raw": "https://mis.twse.com.tw/stock/data/all_etf.txt", "protocol": "https", "host": [ "mis", "twse", "com", "tw" ], "path": [ "stock", "data", "all_etf.txt" ] } }, "response": [] }, { "name": "[櫃買] 00 三大法人明細", "request": { "method": "GET", "header": [], "url": { "raw": "https://www.tpex.org.tw/web/stock/3insti/daily_trade/3itrade_hedge_result.php?l=zh_tw&o=json&se=EW&t=D&d={{TPEX_EXPORT_DATE}}&s=0,asc", "protocol": "https", "host": [ "www", "tpex", "org", "tw" ], "path": [ "web", "stock", "3insti", "daily_trade", "3itrade_hedge_result.php" ], "query": [ { "key": "l", "value": "zh_tw" }, { "key": "o", "value": "json" }, { "key": "se", "value": "EW" }, { "key": "t", "value": "D" }, { "key": "d", "value": "{{TPEX_EXPORT_DATE}}" }, { "key": "s", "value": "0,asc" } ] } }, "response": [] }, { "name": "[櫃買] 01 融資融券明細", "request": { "method": "GET", "header": [], "url": { "raw": "https://www.tpex.org.tw/web/stock/margin_trading/margin_balance/margin_bal_result.php?l=zh_tw&o=json&d={{TPEX_EXPORT_DATE}}", "protocol": "https", "host": [ "www", "tpex", "org", "tw" ], "path": [ "web", "stock", "margin_trading", "margin_balance", "margin_bal_result.php" ], "query": [ { "key": "l", "value": "zh_tw" }, { "key": "o", "value": "json" }, { "key": "d", "value": "{{TPEX_EXPORT_DATE}}" } ] } }, "response": [] }, { "name": "[櫃買] 02 鉅額交易明細", "request": { "method": "GET", "header": [], "url": { "raw": "https://www.tpex.org.tw/web/stock/block_trade/daily_qutoes/block_day_download.php?l=zh_tw&d={{TPEX_EXPORT_DATE}}&s=0,asc,0&charset=UTF-8", "protocol": "https", "host": [ "www", "tpex", "org", "tw" ], "path": [ "web", "stock", "block_trade", "daily_qutoes", "block_day_download.php" ], "query": [ { "key": "l", "value": "zh_tw" }, { "key": "d", "value": "{{TPEX_EXPORT_DATE}}" }, { "key": "s", "value": "0,asc,0" }, { "key": "charset", "value": "UTF-8" } ] } }, "response": [] }, { "name": "[櫃買] 03 當沖明細", "request": { "method": "GET", "header": [], "url": { "raw": "https://www.tpex.org.tw/web/stock/trading/intraday_stat/intraday_trading_stat_download.php?l=zh-tw&d={{TPEX_EXPORT_DATE}}&s=0,asc,0&charset=UTF-8", "protocol": "https", "host": [ "www", "tpex", "org", "tw" ], "path": [ "web", "stock", "trading", "intraday_stat", "intraday_trading_stat_download.php" ], "query": [ { "key": "l", "value": "zh-tw" }, { "key": "d", "value": "{{TPEX_EXPORT_DATE}}" }, { "key": "s", "value": "0,asc,0" }, { "key": "charset", "value": "UTF-8" } ] } }, "response": [] }, { "name": "[櫃買] 04 融券借券", "request": { "method": "GET", "header": [], "url": { "raw": "https://www.tpex.org.tw/web/stock/margin_trading/margin_sbl/margin_sbl_download.php?l=zh-tw&d={{TPEX_EXPORT_DATE}}&s=0,asc,0&charset=utf-8", "protocol": "https", "host": [ "www", "tpex", "org", "tw" ], "path": [ "web", "stock", "margin_trading", "margin_sbl", "margin_sbl_download.php" ], "query": [ { "key": "l", "value": "zh-tw" }, { "key": "d", "value": "{{TPEX_EXPORT_DATE}}" }, { "key": "s", "value": "0,asc,0" }, { "key": "charset", "value": "utf-8" } ] } }, "response": [] }, { "name": "[集保] 01 股權分散表最新週報", "request": { "method": "GET", "header": [], "url": { "raw": "https://smart.tdcc.com.tw/opendata/getOD.ashx?id=1-5", "protocol": "https", "host": [ "smart", "tdcc", "com", "tw" ], "path": [ "opendata", "getOD.ashx" ], "query": [ { "key": "id", "value": "1-5" } ] } }, "response": [] }, { "name": "[集保] 02 股權分散表\b結算日期", "request": { "method": "POST", "header": [ { "key": "Content-Type", "name": "Content-Type", "type": "text", "value": "application/x-www-form-urlencoded" }, { "key": "Referer", "type": "text", "value": "https://www.tdcc.com.tw/smWeb/QryStockAjax.do" } ], "body": { "mode": "urlencoded", "urlencoded": [ { "key": "REQ_OPR", "value": "qrySelScaDates", "type": "text" } ] }, "url": { "raw": "https://www.tdcc.com.tw/smWeb/QryStockAjax.do", "protocol": "https", "host": [ "www", "tdcc", "com", "tw" ], "path": [ "smWeb", "QryStockAjax.do" ] } }, "response": [] }, { "name": "[集保] 03 股權分散表個股", "request": { "method": "POST", "header": [ { "key": "Content-Type", "name": "Content-Type", "value": "application/x-www-form-urlencoded", "type": "text" }, { "key": "Referer", "value": "https://www.tdcc.com.tw/smWeb/QryStockAjax.do", "type": "text" } ], "body": { "mode": "urlencoded", "urlencoded": [ { "key": "scaDate", "value": "20190119", "type": "text" }, { "key": "SqlMethod", "value": "StockNo", "type": "text" }, { "key": "REQ_OPR", "value": "SELECT", "type": "text" }, { "key": "clkStockNo", "value": "3049", "type": "text" } ] }, "url": { "raw": "https://www.tdcc.com.tw/smWeb/QryStockAjax.do", "protocol": "https", "host": [ "www", "tdcc", "com", "tw" ], "path": [ "smWeb", "QryStockAjax.do" ] } }, "response": [] }, { "name": "[分點] 00 券商地址 - TODO", "request": { "method": "GET", "header": [], "url": { "raw": "" } }, "response": [] }, { "name": "[分點] 01 股務代理 - TODO", "request": { "method": "GET", "header": [], "url": { "raw": "" } }, "response": [] }, { "name": "[財報] 00 會計師查核", "request": { "method": "POST", "header": [ { "key": "Content-Type", "name": "Content-Type", "value": "application/x-www-form-urlencoded", "type": "text" } ], "body": { "mode": "urlencoded", "urlencoded": [ { "key": "TYPEK", "value": "sii", "type": "text" }, { "key": "year", "value": "107", "type": "text" }, { "key": "season", "value": "04", "type": "text" }, { "key": "isQuery", "value": "Y", "type": "text" }, { "key": "off", "value": "1", "type": "text" }, { "key": "firstin", "value": "1", "type": "text" }, { "key": "step", "value": "1", "type": "text" }, { "key": "encodeURIComponent", "value": "1", "type": "text" } ] }, "url": { "raw": "https://mops.twse.com.tw/mops/web/t163sb14", "protocol": "https", "host": [ "mops", "twse", "com", "tw" ], "path": [ "mops", "web", "t163sb14" ] } }, "response": [] }, { "name": "[財報] 01 資產負債 - TODO", "request": { "method": "GET", "header": [], "url": { "raw": "" } }, "response": [] }, { "name": "[財報] 02 損益 - TODO", "request": { "method": "GET", "header": [], "url": { "raw": "" } }, "response": [] }, { "name": "[財報] 03 現金流量 - TODO", "request": { "method": "GET", "header": [], "url": { "raw": "" } }, "response": [] }, { "name": "[財報] 04 股東權益 - TODO", "request": { "method": "GET", "header": [], "url": { "raw": "" } }, "response": [] }, { "name": "[大股東] 00 上市大股東股權異動", "request": { "method": "GET", "header": [], "url": { "raw": "https://siis.twse.com.tw/publish/sii/106IRB110_01.HTM", "protocol": "https", "host": [ "siis", "twse", "com", "tw" ], "path": [ "publish", "sii", "106IRB110_01.HTM" ] } }, "response": [] }, { "name": "[大股東] 01 上櫃大股東股權異動", "request": { "method": "GET", "header": [], "url": { "raw": "https://siis.twse.com.tw/publish/otc/107IRB110_12.HTM", "protocol": "https", "host": [ "siis", "twse", "com", "tw" ], "path": [ "publish", "otc", "107IRB110_12.HTM" ] } }, "response": [] }, { "name": "[大股東] 02 興櫃大股東股權異動", "request": { "method": "GET", "header": [], "url": { "raw": "https://siis.twse.com.tw/publish/rotc/106IRB110_01.HTM", "protocol": "https", "host": [ "siis", "twse", "com", "tw" ], "path": [ "publish", "rotc", "106IRB110_01.HTM" ] } }, "response": [] } ], "event": [ { "listen": "prerequest", "script": { "id": "2a60f749-9ad5-4f69-91c7-981502d34dd4", "type": "text/javascript", "exec": [ "" ] } }, { "listen": "test", "script": { "id": "716c094f-8f7b-42e6-98ee-e62977e4633d", "type": "text/javascript", "exec": [ "" ] } } ] } ================================================ FILE: postman/TWMKT.postman_environment.json ================================================ { "id": "e09139ab-0991-4315-82ef-93998a367e54", "name": "TWMKT", "values": [ { "key": "TWSE_EXFORMAT", "value": "json", "enabled": true }, { "key": "TWSE_EXDATE", "value": "20191015", "enabled": true }, { "key": "TPEX_EXPORT_DATE", "value": "108/10/01", "enabled": true } ], "_postman_variable_scope": "environment", "_postman_exported_at": "2019-10-23T04:15:07.097Z", "_postman_exported_using": "Postman/7.9.0" } ================================================ FILE: requirements.txt ================================================ beautifulsoup4>=4.7.1 busm>=0.9.0 lxml>=4.3.3 requests>=2.21.0 pandas>=0.24.2 PyYAML>=5.1.2 # 只有 ticksmap 需要用到 wxWidget # wxPython>=4.0.4 ================================================ FILE: setup.py ================================================ from setuptools import setup, find_packages import twnews.common as common # Load reStructedText description. # Online Editor - http://rst.ninjs.org/ # Quick Reference - http://docutils.sourceforge.net/docs/user/rst/quickref.html readme = open('README.md', 'r') longdesc = readme.read() readme.close() # See # https://packaging.python.org/tutorials/packaging-projects/ # https://python-packaging.readthedocs.io/en/latest/non-code-files.html setup( name='twnews', version=common.VERSION, description='To tear down news web pages in Taiwan.', long_description=longdesc, long_description_content_type='text/markdown', packages=find_packages(), url='https://github.com/virus-warnning/twnews', license='MIT', author='Raymond Wu', package_data={ 'twnews': ['conf/*', 'res/*', 'samples/*', 'tests/soup/*', 'tests/search/*'] }, install_requires=[ 'beautifulsoup4>=4.7.1', 'busm>=0.9.0', 'lxml>=4.3.3', 'requests>=2.21.0', 'pandas>=0.24.2', 'PyYAML>=5.1.2' ], python_requires='>=3.5' ) ================================================ FILE: twnews/__init__.py ================================================ """ twnews 套件載入前作業,用來解決 Windows 環境會發生的編碼問題 """ import sys import locale import _locale # 以下是魔法不要亂改 if locale.getpreferredencoding() == 'cp950': # pylint: disable=protected-access, global-statement # 編碼是 CP950 就強制轉 UTF-8 _locale._getdefaultlocale = (lambda *args: ['zh_TW', 'utf-8']) # 置換 Python 3.5 的 print() 避免轉碼錯誤 VERSION = sys.version_info if VERSION.major == 3 and VERSION.minor == 5: NATIVE_PRINT = __builtins__['print'] def _replaced_print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False): """ 替換用的 print() """ global NATIVE_PRINT filtered = [] for obj in objects: if isinstance(obj, str): filtered.append(obj.encode('cp950', 'ignore').decode('cp950')) else: filtered.append(obj) NATIVE_PRINT(*filtered, sep=sep, end=end, file=file, flush=flush) __builtins__['print'] = _replaced_print ================================================ FILE: twnews/__main__.py ================================================ """ 工具程式 """ import sys import locale import os.path from datetime import datetime from twnews.common import get_logger, VERSION from twnews.soup import NewsSoup from twnews.search import NewsSearch def soup(path): """ 分解新聞 """ print('-' * 75) nsoup = NewsSoup(path) print('原始路徑: {}'.format(path)) print('最終路徑: {}'.format(nsoup.path)) print('頻道: {}'.format(nsoup.channel)) print('標題: {}'.format(nsoup.title())) ndt = nsoup.date() if ndt is not None: print('日期: {}'.format(ndt.strftime('%Y-%m-%d %H:%M:%S'))) else: print('日期: None') print('記者: {}'.format(nsoup.author())) print('內文:') print(nsoup.contents()) print('有效內容率: {:.2f}%'.format(nsoup.effective_text_rate() * 100)) print('-' * 75) def search_and_list(keyword, channel): """ 搜尋,然後列出新聞標題 """ print('測試搜尋') nsearch = NewsSearch(channel, limit=10) results = nsearch.by_keyword(keyword).to_dict_list() logger = get_logger() for (i, result) in enumerate(results): try: print('{:03d}: {}'.format(i, result['title'])) print(' 日期: {}'.format(result['date'])) print(' 連結: {}'.format(result['link'])) except ValueError as ex: logger.error('例外類型: %s', type(ex).__name__) logger.error(ex) def search_and_soup(keyword, channel): """ 搜尋,然後分解新聞 """ print('測試搜尋與分解, 搜尋中 ...', end='', flush=True) logger = get_logger() nsearch = NewsSearch(channel, limit=10) nsoups = nsearch.by_keyword(keyword).to_soup_list() print('\r測試搜尋與分解' + ' ' * 20, flush=True) for (i, nsoup) in enumerate(nsoups): try: print('{:03d}: {}'.format(i, nsoup.path)) print(' 記者: {} / 日期: {}'.format(nsoup.author(), nsoup.date())) print(' 標題: {}'.format(nsoup.title())) print(' {} ...'.format(nsoup.contents(30)), flush=True) except ValueError as ex: logger.error('例外類型: %s', type(ex).__name__) logger.error(ex) def search_and_compare_performance(keyword): """ 測試各新聞台搜尋效能 """ print('測試各新聞台搜尋效能') summary = {} for channel in ['appledaily', 'cna', 'ettoday', 'ltn', 'setn', 'udn']: print() print(channel) print('-' * 60) summary[channel] = [] for repeat in range(3): nsearch = NewsSearch(channel, limit=100) nsearch.by_keyword(keyword) results = nsearch.to_dict_list() total = len(results) tpp = nsearch.elapsed() / nsearch.pages() tpr = nsearch.elapsed() / total summary[channel].append(tpp) msg = '{:03d}: {:.3f} 秒/頁, {:.3f} 秒/筆, 共 {} 頁, 總耗時: {:.3f} 秒' print(msg.format(repeat, tpp, tpr, nsearch.pages(), nsearch.elapsed())) print('-' * 60) print() print('Markdown 摘要表:') print() print('  | 1st | 2nd | 3rd') print('---- | ---- | ---- | ----') for (channel, samples) in summary.items(): print(channel, end='') for sample in samples: print(' | {:.3f}'.format(sample), end='') print() print() def compare_keyword(keyword): """ 比較關鍵字在各媒體的出現次數 """ print('比較上個月 "{}" 在各媒體標題出現次數'.format(keyword)) now = datetime.now() nts = now.timestamp() nts = nts - nts % 86400 day_lmon = datetime.fromtimestamp(nts - 86400 * now.day).day beg_date = datetime(now.year, now.month - 1, 1).strftime('%Y-%m-%d') end_date = datetime(now.year, now.month - 1, day_lmon).strftime('%Y-%m-%d') print('時間區間: {} ~ {}'.format(beg_date, end_date)) media = { 'appledaily': ' 蘋果', 'cna': '中央社', 'ettoday': ' 東森', 'ltn': ' 自由', 'setn': ' 三立', 'udn': ' 聯合' } for (channel, name) in media.items(): nsearch = NewsSearch( channel, beg_date=beg_date, end_date=end_date, limit=999 ) results = nsearch.by_keyword(keyword, title_only=True).to_dict_list() msg = '{}: {}'.format(name, len(results)) print(msg, flush=True) def usage(): """ 使用說明 """ print('twnews {} (預設編碼: {})'.format( VERSION, locale.getpreferredencoding())) print() usage_path = os.path.dirname(__file__) + '/conf/usage.txt' with open(usage_path, 'r') as usage_file: print(usage_file.read()) def get_cmd_param(index, default=None): """ 取得 shell 參數 """ if len(sys.argv) > index: return sys.argv[index] return default def main(): """ main() """ action = get_cmd_param(1) if action == 'soup': keyword = get_cmd_param( 2, 'https://tw.news.appledaily.com/local/realtime/20181025/1453825') soup(keyword) elif action == 'search': keyword = get_cmd_param(2, '酒駕') channel = get_cmd_param(3, 'appledaily') search_and_list(keyword, channel) elif action == 'snsp': keyword = get_cmd_param(2, '酒駕') channel = get_cmd_param(3, 'appledaily') search_and_soup(keyword, channel) elif action == 'sncp': keyword = get_cmd_param(2, '酒駕') search_and_compare_performance(keyword) elif action == 'cpkw': keyword = get_cmd_param(2, '酒駕') compare_keyword(keyword) else: if action != 'help': print('動作名稱錯誤') print() usage() if __name__ == '__main__': main() ================================================ FILE: twnews/cache.py ================================================ """ 快取處理模組 """ import os import lzma import json class DateCache: """ 處理日期命名快取 """ def __init__(self, category, item, data_format): """ 建立日期命名快取 """ self.category = category self.item = item self.data_format = data_format def get_path(self, datestr): """ 產生快取檔路徑 """ cache_dir = os.path.expanduser('~/.twnews/cache/' + self.category) if not os.path.isdir(cache_dir): os.makedirs(cache_dir) return '%s/%s-%s.%s.xz' % (cache_dir, self.item, datestr, self.data_format) def has(self, datestr): """ 檢查快取檔是否存在 """ cache_path = self.get_path(datestr) return os.path.isfile(cache_path) def load(self, datestr): """ 載入快取檔 """ content = None cache_path = self.get_path(datestr) with lzma.open(cache_path, 'rt') as f_cache: if self.data_format == 'json': content = json.load(f_cache) else: content = f_cache.read() return content def save(self, datestr, content): """ 儲存快取檔 """ cache_path = self.get_path(datestr) with lzma.open(cache_path, 'wt') as f_cache: if self.data_format == 'json': json.dump(content, f_cache) else: f_cache.write(content) ================================================ FILE: twnews/common.py ================================================ """ twnews 共用項目 """ import json import os import os.path import logging import logging.config import socket import yaml import requests import requests.packages.urllib3.util.connection as urllib3_conn # 強制 requests 使用 IPv4 urllib3_conn.allowed_gai_family = lambda: socket.AF_INET # pylint: disable=global-statement __LOGGER_LOADED = False __ALLCONF = None __SESSION = { "direct": None, "proxy": None } VERSION = '0.3.3' def found_socks5(): """ 檢查是否有 SOCKS 5 Proxy """ found = False with socket.socket(socket.AF_INET) as sock: try: sock.connect(('localhost', 9050)) found = True except socket.error: pass finally: sock.close() return found def get_package_dir(): """ 取得套件根目錄,用來定位套件內資源 """ return os.path.dirname(__file__) def get_logger(name='news'): """ 取得 logger 如果已經存在就使用現有的 """ global __LOGGER_LOADED if not __LOGGER_LOADED: logdir = os.path.expanduser('~/.twnews/log') if not os.path.isdir(logdir): os.makedirs(logdir) cfg_yaml = '{}/conf/logging.yaml'.format(get_package_dir()) with open(cfg_yaml, 'r') as cfg_file: cfg_dict = yaml.load(cfg_file, Loader=yaml.SafeLoader) for hname in cfg_dict['handlers']: handler = cfg_dict['handlers'][hname] if 'filename' in handler and handler['filename'].startswith('~'): handler['filename'] = os.path.expanduser(handler['filename']) logging.config.dictConfig(cfg_dict) __LOGGER_LOADED = True logger = None if __LOGGER_LOADED: logger = logging.getLogger(name) return logger def get_session(proxy_first): """ 取得 requests session 如果已經存在就使用現有的 """ global __SESSION logger = get_logger('common') if proxy_first and found_socks5(): logger.debug('透過 proxy 連線') session_type = 'proxy' else: session_type = 'direct' if __SESSION[session_type] is None: logger.debug('建立新的 session') user_agent = 'Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) ' \ + 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36' __SESSION[session_type] = requests.Session() __SESSION[session_type].headers.update({ "Accept": "text/html,application/xhtml+xml,application/xml", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7", "Cache-Control": "max-age=0", "Connection": "keep-alive", "User-Agent": user_agent }) if session_type == 'proxy': __SESSION[session_type].proxies = { 'http': 'socks5h://localhost:9050', 'https': 'socks5h://localhost:9050' } else: logger.debug('使用現有 session') return __SESSION[session_type] def get_all_conf(): """ 取得完整設定 """ global __ALLCONF if __ALLCONF is None: soup_cfg = '{}/conf/news-soup.json'.format(get_package_dir()) with open(soup_cfg, 'r') as conf_file: __ALLCONF = json.load(conf_file) return __ALLCONF def detect_channel(path): """ 偵測路徑對應的新聞頻道 """ all_conf = get_all_conf() for channel in all_conf: if channel in path: return channel return '' def get_channel_conf(channel, action=None): """ 載入新聞台設定 """ all_conf = get_all_conf() if channel in all_conf: chconf = all_conf[channel] if action is None: return chconf if action in chconf: return chconf[action] return None def get_cache_dir(category): """ 取得快取目錄 """ logger = get_logger() cache_dir = os.path.expanduser('~/.twnews/cache/' + category) if not os.path.isdir(cache_dir): logger.debug('建立快取目錄: %s', cache_dir) os.makedirs(cache_dir) logger.debug('使用快取目錄: %s', cache_dir) return cache_dir ================================================ FILE: twnews/conf/logging.yaml ================================================ version: 1 disable_existing_loggers: true formatters: standard: datefmt: '%Y-%m-%d %H:%M:%S' format: '[%(asctime)s] %(levelname)-7s | %(message)s' simple: datefmt: '%H:%M:%S' format: '[%(asctime)s] %(name)-7s | %(levelname)-7s | %(message)s' handlers: common_log: level: DEBUG formatter: standard class: logging.handlers.TimedRotatingFileHandler filename: '~/.twnews/log/common.log' when: 'D' news_log: level: DEBUG formatter: standard class: logging.handlers.TimedRotatingFileHandler filename: '~/.twnews/log/news.log' when: 'D' finance_log: level: DEBUG formatter: standard class: logging.handlers.TimedRotatingFileHandler filename: '~/.twnews/log/finance.log' when: 'D' stdout: level: ERROR formatter: simple class: logging.StreamHandler stream: ext://sys.stdout telegram: level: INFO formatter: simple class: busm.BusmHandler subject: finance crawler loggers: common: level: DEBUG handlers: - common_log - stdout news: level: DEBUG handlers: - news_log - stdout finance: level: DEBUG handlers: - finance_log - telegram - stdout ================================================ FILE: twnews/conf/news-soup.json ================================================ { "what's that": { "name": "頻道名稱", "layout_list": [ { "name": "特殊排版名稱", "prefix": "特殊排版網址" } ], "mobile": { "title_node": "標題所在的 CSS selector", "date_node": "日期時間所在的 CSS Selector", "date_format": "日期時間的格式,會用 datetime.strptime 處理", "author_node": "記者所在的 CSS selector,空字串表示記者姓名在內文中,程式會自動偵測", "article_node": "內文所在的 CSS selector" }, "search": { "url": "搜尋網址形式", "begin_date_format": "開始日期參數形式", "end_date_format": "結束日期參數形式", "result_node": "搜尋結果位置", "title_node": "標題位置,相對於搜尋結果", "link_node": "連結位置,相對於搜尋結果", "date_node": "日期位置,相對於搜尋結果", "date_format": "日期格式" } }, "appledaily": { "name": "蘋果日報", "layout_list": [ { "layout": "home", "prefix": "http://home.appledaily.com.tw/" } ], "mobile": { "title_node": "article.nm-content > div.nm-article > header > h2", "date_node": "article.nm-content > div.nm-article > header > div.time-and-share > time", "date_format": "建立時間:%Y/%m/%d %H:%M", "author_node": "", "article_node": "article.nm-content > div.nm-article > div.nm-article-body > div.text" }, "home": { "title_node": "#maincontent > section > div.ncbox_cont > h1", "date_node": "#maincontent > section > div.ncbox_cont > div.nctimeshare > time", "date_format": "%Y年%m月%d日", "author_node": "", "article_node": "#maincontent > section > div.ncbox_cont > div.articulum > p" }, "search": { "url": "https://tw.appledaily.com/search/ajaxresult/page/${PAGE}?querystrS=${KEYWORD}&sort=time&searchType=all", "begin_date_format": "&dateStart=%Y/%m/%d", "end_date_format": "&dateEnd=%Y/%m/%d", "result_node": "", "title_node": "title", "link_node": "sharing > url", "date_node": "pubDate", "date_format": "%Y%m%d" } }, "chinatimes": { "name": "中時電子報", "layout_list": [], "mobile": { "title_node": "article.article-box h1.article-title", "date_node": "article.article-box div.meta-info > time", "date_with_children": true, "date_format": "%H:%M%Y/%m/%d", "author_node": "article.article-box div.author > a", "article_node": "article.article-box div.article-body > p" } }, "cna": { "name": "中央社", "layout_list": [], "mobile": { "title_node": "div.centralContent > h1", "date_node": "div.centralContent > div.timeBox > div.updatetime > span", "date_format": "%Y/%m/%d %H:%M", "author_node": "", "article_node": "div.centralContent > div.paragraph > p" }, "search": { "url": "https://www.cna.com.tw/cna2018api/api/simplelist/searchkeyword/${KEYWORD}/pageidx/${PAGE}/", "result_node": "result > SimpleItems", "link_node": "PageUrl", "title_node": "HeadLine", "date_node": "CreateTime", "date_format": "%Y/%m/%d %H:%M" } }, "ettoday": { "name": "東森新聞雲", "layout_list": [ { "layout": "fashion", "prefix": "https://fashion.ettoday.net/" }, { "layout": "game", "prefix": "https://game.ettoday.net/" }, { "layout": "health", "prefix": "https://health.ettoday.net/" }, { "layout": "game", "prefix": "https://house.ettoday.net/" }, { "layout": "game", "prefix": "https://pets.ettoday.net/" }, { "layout": "speed", "prefix": "https://speed.ettoday.net/" }, { "layout": "game", "prefix": "https://sports.ettoday.net/" }, { "layout": "game", "prefix": "https://star.ettoday.net/" }, { "layout": "health", "prefix": "https://travel.ettoday.net/" } ], "mobile": { "title_node": "div.subject_news > header > h1", "date_node": "span.date > time", "date_format": "%Y年%m月%d日 %H:%M", "author_node": "", "article_node": "div.subject_news > div.story > p" }, "fashion": { "title_node": "header > h1", "date_node": "time.date", "date_format": "%Y/%m/%d %H:%M", "author_node": "", "article_node": "article div.story > p" }, "game": { "title_node": "article h1.title", "date_node": "time", "date_format": "%Y年%m月%d日 %H:%M", "author_node": "", "article_node": "article div.story > p" }, "health": { "title_node": "header > h1", "date_node": "time", "date_format": "時間: %Y年%m月%d日 %H:%M", "author_node": "", "article_node": "article div.story > p" }, "speed": { "title_node": "article h1.title", "date_node": "time", "date_format": "%Y-%m-%d %H:%M", "author_node": "", "article_node": "article div.story > p" }, "search": { "url": "https://www.ettoday.net/news_search/doSearch.php?keywords=${KEYWORD}&page=${PAGE}&daydiff=3&idx=1", "last_page": "div.page_nav > div.menu_page > p.info", "page_pattern": "共(\\d+)頁", "result_node": "#result-list > div.archive", "link_node": "div.box_2 > h2 > a", "title_node": "div.box_2 > h2 > a", "date_node": "div.box_2 > p.detail > span.date", "date_pattern": "\\d{4}-\\d{2}-\\d{2}", "date_format": "%Y-%m-%d" } }, "ltn": { "name": "自由時報", "layout_list": [ { "layout": "3c", "prefix": "https://3c.ltn.com.tw" }, { "layout": "auto", "prefix": "https://auto.ltn.com.tw" }, { "layout": "ec", "prefix": "https://ec.ltn.com.tw" }, { "layout": "ent", "prefix": "https://ent.ltn.com.tw" }, { "layout": "estate", "prefix": "https://estate.ltn.com.tw" }, { "layout": "food", "prefix": "https://food.ltn.com.tw" }, { "layout": "istyle", "prefix": "https://istyle.ltn.com.tw" }, { "layout": "market", "prefix": "https://market.ltn.com.tw" }, { "layout": "playing", "prefix": "https://playing.ltn.com.tw" }, { "layout": "sports", "prefix": "https://sports.ltn.com.tw" }, { "layout": "talk", "prefix": "https://talk.ltn.com.tw" } ], "mobile": { "title_node": "div.com > h2", "date_node": "div.com > div.h2_else > div.time", "date_format": [ "%Y-%m-%d %H:%M", "%Y-%m-%d" ], "author_node": "", "article_node": "div.com > div.boxTitle > p" }, "3c": { "title_node": "section.nbox > h1", "date_node": "section.nbox > span.writer > span:nth-of-type(1)", "date_format": "%Y-%m-%d %H:%M", "author_node": "section.nbox > span.writer > span:nth-of-type(2)", "article_node": "div.boxTitle > p" }, "auto": { "title_node": "section > div.title_box > h1", "date_node": "section > div.title_box > div.unit_else", "date_format": "%Y/%m/%d", "author_node": "section > div.title_box > div.unit_else", "article_node": "section > div.detail > p" }, "ec": { "title_node": "article.com > h1", "date_node": "article.com > div.h1_else > div.time", "date_format": "%Y-%m-%d %H:%M:%S", "author_node": "", "article_node": "article.com > div.textbody > p" }, "ent": { "title_node": "div.news_content > h1", "date_node": "div.news_content > div.author > div.date", "date_format": "%Y/%m/%d %H:%M", "author_node": "", "article_node": "div.news_content > p" }, "estate": { "title_node": "div.container > h1", "date_node": "div.container > p.author > span.time", "date_format": "%Y/%m/%d %H:%M", "author_node": "div.container > p.author", "article_node": "div.container > div.wordright > p" }, "food": { "title_node": "section > div.context > h2", "date_node": "section > div.context > b.date", "date_format": "%Y/%m/%d", "author_node": "", "article_node": "section > div.context > p" }, "istyle": { "title_node": "div.content > div.title_box > h1", "date_node": "div.content > div.title_box > div.unit_else", "date_format": "%b. %d %Y", "author_node": "div.content > div.title_box > div.unit_else", "article_node": "div.content > div.article_content > p" }, "market": { "title_node": "div.com > h2", "date_node": "div.com > div.h2_else > div.time", "date_format": "%Y-%m-%d %H:%M", "author_node": "", "article_node": "div.com > div.h2_else > p" }, "playing": { "title_node": "div.left_content > div.article_header > h1", "date_node": "div.left_content > div.article_header > div.author > span:nth-of-type(2)", "date_format": "%Y-%m-%d", "author_node": "div.left_content > div.article_header > div.author > span:nth-of-type(1)", "article_node": "div.left_content > div.article_body > div.text > p" }, "sports": { "title_node": "div.news_content > h1", "date_node": "div.news_content > div.author > div.date", "date_format": "%Y/%m/%d %H:%M", "author_node": "", "article_node": "div.news_content > p" }, "talk": { "title_node": "div.conbox > h1", "date_node": "div.conbox > div.top_share > div.writer > a > span:nth-of-type(2) > div.mobile_none", "date_format": "%Y-%m-%d %H:%M", "author_node": "div.conbox > div.top_share > div.writer > a > span:nth-of-type(2)", "article_node": "div.conbox > div.cont > p" }, "search": { "url": "https://m.ltn.com.tw/search/${PAGE}?q=${KEYWORD}", "begin_date_format": "&start=%Y-%m-%d", "end_date_format": "&end=%Y-%m-%d", "result_node": "ul.news > li", "link_node": "a", "title_node": "a > p", "date_node": "a > span", "date_format": "%Y-%m-%d" } }, "setn": { "name": "三立新聞網", "layout_list": [ { "layout": "entertainment", "prefix": "https://www.setn.com/e/" } ], "mobile": { "title_node": "section.news-all-area > h1", "date_node": "section.news-all-area > div.page-date > time", "date_format": "%Y-%m-%d %H:%M", "author_node": "", "article_node": "#ckuse > article > p" }, "entertainment": { "title_node": "div.content1 > div.title > h1", "date_node": "div.content1 > div.title > div.titleBtnBlock > div.time", "date_format": "%Y/%m/%d %H:%M:%S", "author_node": "", "article_node": "div.Content2 > p" }, "search": { "url": "https://www.setn.com/m/search.aspx?q=${KEYWORD}&p=${PAGE}", "result_node": "div.news-area", "link_node": "div.news-info > div.news-word > a", "title_node": "div.news-info > div.news-word > a", "date_node": "div.news-info > div.lable-date", "date_format": "%Y/%m/%d %H:%M" } }, "udn": { "name": "聯合新聞網", "layout_list": [ { "layout": "autos", "prefix": "https://autos.udn.com" }, { "layout": "game", "prefix": "https://game.udn.com" }, { "layout": "global", "prefix": "https://global.udn.com" }, { "layout": "game", "prefix": "https://health.udn.com" }, { "layout": "house", "prefix": "https://house.udn.com" }, { "layout": "nba", "prefix": "https://nba.udn.com" }, { "layout": "opinion", "prefix": "https://opinion.udn.com" }, { "layout": "running", "prefix": "https://running.udn.com" }, { "layout": "stars", "prefix": "https://stars.udn.com" }, { "layout": "style", "prefix": "https://style.udn.com" }, { "layout": "vision", "prefix": "https://vision.udn.com" } ], "mobile": { "title_node": "#story_body_content > h1", "date_node": "#story_bady_info > div.story_bady_info_author > span", "date_format": "%Y-%m-%d %H:%M", "author_node": "#story_bady_info > div.story_bady_info_author > a", "article_node": "#story_body_content > p" }, "autos": { "title_node": "#story_art_title", "date_node": "#shareBar > div.shareBar__info > div.shareBar__info--author > span", "date_format": "%Y-%m-%d %H:%M:%S", "author_node": "#shareBar > div.shareBar__info > div.shareBar__info--author", "article_node": "#story_body_content > p" }, "game": { "title_node": "#story_art_title", "date_node": "#shareBar > div.shareBar__info > div.shareBar__info--author > span", "date_format": "%Y-%m-%d %H:%M", "author_node": "#shareBar > div.shareBar__info > div.shareBar__info--author", "article_node": "#story_body_content > p" }, "global": { "title_node": "#story_art_title", "date_node": "#story_bady_info", "date_format": "%Y/%m/%d", "author_node": "", "article_node": "#story_body > div.story_body_content > p" }, "house": { "title_node": "#story_art_title", "date_node": "#shareBar > div.shareBar__info > div.shareBar__info--author > span", "date_format": "%Y-%m-%d %H:%M:%S", "author_node": "#shareBar > div.shareBar__info > div.shareBar__info--author", "article_node": "#story_body_content > p" }, "nba": { "title_node": "#story_body_content > h1", "date_node": "#shareBar > div.shareBar__info > div.shareBar__info--author > span", "date_format": "%Y-%m-%d %H:%M", "author_node": "#shareBar > div.shareBar__info > div.shareBar__info--author", "article_node": "#story_body_content > span > p" }, "opinion": { "title_node": "#container > main > h1", "date_node": ".story_bady_info_author > time", "date_format": "%Y/%m/%d", "author_node": ".story_bady_info_author > .story_bady_info > a", "article_node": "#container > main > p" }, "stars": { "title_node": "#story_art_title", "date_node": "#shareBar > div.shareBar__info > div.shareBar__info--author > span", "date_format": "%Y-%m-%d %H:%M", "author_node": "#shareBar > div.shareBar__info > div.shareBar__info--author", "article_node": "#story > p" }, "style": { "title_node": "#story_art_title > font", "date_node": "#shareBar > div.shareBar__info > div.shareBar__info--author > span", "date_format": "%Y-%m-%d %H:%M", "author_node": "#shareBar > div.shareBar__info > div.shareBar__info--author", "article_node": "#story-main > p" }, "search": { "url": "https://udn.com/search/result/2/${KEYWORD}/${PAGE}", "last_page": "#result_list > div.pagelink > span.total", "page_pattern": "共 (\\d+) 頁", "result_node": "#search_content > dt", "link_node": "a", "title_node": "a > h2", "date_node": "a > span.cat", "date_pattern": "\\d{4}/\\d{2}/\\d{2}", "date_format": "%Y/%m/%d" } } } ================================================ FILE: twnews/conf/usage.txt ================================================ 用法: python3 -m twnews 動作 動作列表: soup [路徑] 分解一則新聞,路徑可以是新聞網址或檔案路徑 search [關鍵字] [頻道] 關鍵字搜尋新聞,取10筆,列出搜尋結果 snsp [關鍵字] [頻道] 關鍵字搜尋新聞,取10筆,讀取新聞,分解新聞 sncp [關鍵字] 關鍵字搜尋新聞,取100筆,比較各新聞網站效能 cpkw [關鍵字] 關鍵字搜尋上個月的新聞,統計各家媒體標題出現關鍵字的次數 help 顯示這個訊息 頻道列表: appledaily 蘋果日報 cna 中央社 ettoday 東森新聞雲 ltn 自由時報 setn 三立新聞網 udn 聯合新聞網 預設值: [路徑] https://tw.news.appledaily.com/local/realtime/20181025/1453825 (這是一則上吊新聞) [頻道] appledaily [關鍵字] 酒駕 * 中時電子報雖然不支援搜尋功能,但是分解新聞功能有作用 ================================================ FILE: twnews/exceptions.py ================================================ """ 例外模組 """ class SyncException(Exception): """ 同步資料時觸發的例外 """ def __init__(self, reason): super().__init__() self.reason = reason class NetworkException(SyncException): """ 因網路問題觸發的例外 """ class InvalidDataException(SyncException): """ 因無效資料問題觸發的例外 """ ================================================ FILE: twnews/finance/__init__.py ================================================ """ 財經資料蒐集工具共用模組 """ import os import sqlite3 import sys from requests.exceptions import RequestException import twnews.common as common from twnews.exceptions import NetworkException DDL_LIST = [ # 三大法人 ''' CREATE TABLE IF NOT EXISTS `institution` ( trading_date TEXT, security_id TEXT, security_name TEXT, foreign_trend INTEGER, stic_trend INTEGER, dealer_trend INTEGER, PRIMARY KEY (`trading_date`, `security_id`) ); ''', # 融資融券 ''' CREATE TABLE IF NOT EXISTS `margin` ( trading_date TEXT, security_id TEXT, security_name TEXT, buying_balance INTEGER, selling_balance INTEGER, PRIMARY KEY (`trading_date`, `security_id`) ); ''', # 借券賣出 ''' CREATE TABLE IF NOT EXISTS `short_sell` ( trading_date TEXT, security_id TEXT, security_name TEXT, borrowed INTEGER, selled INTEGER, PRIMARY KEY (`trading_date`, `security_id`) ); ''', # 鉅額交易 ''' CREATE TABLE IF NOT EXISTS `block` ( trading_date TEXT, security_id TEXT, security_name TEXT, tick_rank INTEGER, tick_type TEXT, close REAL, volume INTEGER, total INTEGER, PRIMARY KEY (`trading_date`, `security_id`, `tick_rank`) ); ''', # ETF 淨值折溢價 ''' CREATE TABLE IF NOT EXISTS `etf_offset` ( trading_date TEXT, security_id TEXT, security_name TEXT, close REAL, net REAL, offset REAL, PRIMARY KEY (`trading_date`, `security_id`) ); ''' ] # 股權分散 DDL_DIST = ''' CREATE TABLE IF NOT EXISTS level{:02d} ( `trading_date` TEXT NOT NULL, `security_id` TEXT NOT NULL, `numof_holders` INTEGER NOT NULL, `numof_stocks` INTEGER NOT NULL, `percentof_stocks` REAL NOT NULL, PRIMARY KEY(`trading_date`, `security_id`) ); ''' REPEAT_LIMIT = 3 REPEAT_INTERVAL = 5 def get_connection(rebuild=False): """ 自動產生財經資料庫與取得連線 """ db_dir = os.path.expanduser('~/.twnews/db') if not os.path.isdir(db_dir): os.makedirs(db_dir) db_path = db_dir + '/finance.sqlite' if rebuild: os.remove(db_path) db_ready = os.path.isfile(db_path) db_conn = sqlite3.connect(db_path) if not db_ready: # 產生籌碼資料表 for ddl in DDL_LIST: db_conn.execute(ddl) # 產生各級股權分散表, 有 1~17 級 for level in range(1, 18): ddl = DDL_DIST.format(level) db_conn.execute(ddl) db_conn.commit() return db_conn def get_argument(index, default=''): """ 取得 shell 參數, 或使用預設值 """ if len(sys.argv) <= index: return default return sys.argv[index] def fucking_get(hook, url, params): """ 共用 HTTP GET 處理邏輯 """ session = common.get_session(False) try: resp = session.get(url, params=params) if resp.status_code != 200: msg = 'Got HTTP error, status code: %d' % resp.status_code raise NetworkException(msg) dataset = hook(resp) except RequestException as ex: msg = 'Cannot get response, exception type: %s' % type(ex).__name__ raise NetworkException(msg) return dataset ================================================ FILE: twnews/finance/broker.py ================================================ """ 券商與分公司資訊與門牌定位 已知問題: * 有筆紀錄無法成功定位 1. 8770 大鼎 2. 1115 台灣企銀-太平 3. 779m 國票-中港 4. 9636 富邦-中壢 這 4 筆用工人智慧取經緯度,其餘自動化 * TGOS 服務查詢 500 次的時候,會拒絕之後的 request 可能需要重置 requests session,現階段程式無法一口氣完成 9xx 筆定位 """ import os import re import json import sqlite3 import time import urllib.parse import requests from bs4 import BeautifulSoup from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from sqlalchemy import Column, Integer, String, Float, create_engine from pyproj import Transformer Base = declarative_base() class TradingLocation(Base): """ 分點資料 """ __tablename__ = 'trading_locs' id = Column(String(4), primary_key=True) name = Column(String(100), nullable=False) address = Column(String(100), nullable=False) phone = Column(String(100), nullable=False) parent = Column(String(100), nullable=False, default=-1) lat = Column(Float(), nullable=False, default=0.0) lng = Column(Float(), nullable=False, default=0.0) started_at = Column(String(100), nullable=False) def date_conv(hw_date): """ 民國日期轉西元日期 ISO 格式 """ patterns = [ r'^(\d{2,3})(\d{2})(\d{2})$', r'^(\d{2,3})/(\d{2})/(\d{2})$', ] ad_date = None for pattern in patterns: m = re.match(pattern, hw_date) if not m: continue d_yy = int(m[1]) + 1911 d_mm = int(m[2]) d_dd = int(m[3]) ad_date = '%4d-%02d-%02d' % (d_yy, d_mm, d_dd) break return ad_date def visit_branch(session, parent_id): """ 爬分公司 """ url = 'https://www.twse.com.tw/brokerService/brokerServiceAudit' params = { 'stkNo': parent_id, 'showType': 'list', 'focus': 6 } resp = requests.get(url, params=params) if resp.status_code != 200: exit(1) branches = [] soup = BeautifulSoup(resp.text, 'lxml') table = soup.select('#table6 > table')[0] for row in table.select('tr'): cols = row.select('td') if not cols: continue if cols[0].has_attr('colspan'): break loc = TradingLocation() loc.id = cols[0].text.strip() loc.name = cols[1].text.strip() loc.address = cols[3].text.strip() loc.phone = cols[4].text.strip() loc.started_at = date_conv(cols[2].text.strip()) loc.parent = parent_id session.merge(loc) def visit_parent(session): """ 爬母公司 """ resp = requests.get('https://www.twse.com.tw/zh/brokerService/brokerServiceAudit') if resp.status_code != 200: exit(1) db_path = os.path.expanduser('~/.twnews/db/finance.sqlite') db_conn = sqlite3.connect(db_path) soup = BeautifulSoup(resp.text, 'lxml') table = soup.select('#table2 > table')[0] for row in table.select('tr'): cols = row.select('td') if not cols: continue loc = TradingLocation() loc.id = cols[0].text.strip() loc.name = cols[1].text.strip() loc.address = cols[3].text.strip() loc.phone = cols[4].text.strip() loc.started_at = date_conv(cols[2].text.strip()) session.merge(loc) visit_branch(session, loc.id) def geocode_single(address, req_session, sid, transformer): """ 處理單筆地址定位 """ # 騙到 EPSG:3826 座標 time.sleep(0.5) url = 'https://map.tgos.tw/TGOSCloud/Generic/Project/GHTGOSViewer_Map.ashx' params = { 'method': 'querymoiaddr', 'address': address, 'useoddeven': False, 'sid': sid } resp = req_session.post(url, data=params) if resp.status_code != 200: # print(resp.status_code) return (0.0, 0.0) try: respjson = json.loads(resp.text) except: return (0.0, 0.0) if not respjson['AddressList']: # print(json.dumps(respjson, indent=2)) return (0.0, 0.0) result = json.loads(resp.text)['AddressList'][0] point = transformer.transform(result['X'], result['Y']) return point def geocode(orm_session): # 座標轉換器,只需要做一次 (需要 pyproj) transformer = Transformer.from_crs("EPSG:3826", "EPSG:4326") # 做個給掰的 session # 目前發現偽裝真實用戶只能查 500 個地址,可能需要重置連線才能處理更多資料 req_session = requests.Session() req_session.headers.update({ 'Accept': 'text/html,application/xhtml+xml,application/xml', 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7', 'Cache-Control': 'max-age=0', 'Connection': 'keep-alive', 'User-Agent': 'Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) ' \ + 'AppleWebKit/537.36 (KHTML, like Gecko) ' \ + 'Chrome/46.0.2490.76 Mobile Safari/537.36' }) # 騙到 pagekey, 只需要做一次 url = 'https://map.tgos.tw/TGOSCloud/Web/Map/TGOSViewer_Map.aspx' resp = req_session.get(url) if resp.status_code != 200: print(resp.status_code) exit(1) match = re.search(r"sircPAGEKEY\s?='([^\']+)';", resp.text) if not match: print('無法取得 pagekey') exit(1) pagekey = urllib.parse.unquote(match[1]) # print(pagekey) # 加上這一行其他的 request 才不會被擋掉 req_session.headers['Referer'] = url # 騙到 sid, 只需要做一次 url = 'https://map.tgos.tw/TGOSCloud/Generic/Utility/UG_Handler.ashx' params = { 'method': 'GetSessionID', 'pagekey': pagekey } resp = req_session.post(url, params=params) if resp.status_code != 200: print(resp.status_code) exit(1) fields = json.loads(resp.text) sid = fields['id'] # print(sid) q = orm_session.query(TradingLocation).filter( TradingLocation.lat == 0.0, TradingLocation.lng == 0.0 ) for loc in q.all(): slices = loc.address.split('、') m = re.search('^.+號', slices[0]) if m: fixed_address = m[0] else: fixed_address = slices[0] + '號' (lat, lng) = geocode_single(fixed_address, req_session, sid, transformer) print(loc.id, fixed_address, lat, lng) loc.lat = lat loc.lng = lng orm_session.merge(loc) #orm_session.commit() #address = '台北市114內湖區石潭路151號' #geocode_single(address, req_session, sid, transformer) def main(): db_repl = 'sqlite:///' + os.path.expanduser('~/.twnews/db/finance.sqlite') engine = create_engine(db_repl, echo=True) Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) session = Session() # 爬券商分點 # visit_parent(session) # 券商分點做地理定位 geocode(session) session.commit() if __name__ == '__main__': main() ================================================ FILE: twnews/finance/tdcc.py ================================================ """ 集保中心資料蒐集模組 """ import os import re import sqlite3 import pandas import twnews.common as common from twnews.finance import get_argument, fucking_get, get_connection from twnews.cache import DateCache def import_dist(csv_date='latest'): """ 匯入指定日期的股權分散表到資料庫 """ logger = common.get_logger('finance') csv_dir = common.get_cache_dir('tdcc') if csv_date == 'latest': max_date = '' for filename in os.listdir(csv_dir): match = re.match(r'dist-(\d{8}).csv.xz', filename) if match is not None: if max_date < match.group(1): max_date = match.group(1) csv_date = max_date csv_file = '{}/dist-{}.csv.xz'.format(csv_dir, csv_date) iso_date = re.sub(r'(\d{4})(\d{2})(\d{2})', r'\1-\2-\3', csv_date) if not os.path.isfile(csv_file): logger.error('沒有 TDCC %s 的股權分散表檔案: %s', iso_date, csv_file) return db_conn = get_connection() col_names = [ 'trading_date', 'security_id', 'level', 'numof_holders', 'numof_stocks', 'percentof_stocks' ] # Pandas 會自動偵測 extension 解壓縮, 不需要自幹 dfrm = pandas.read_csv(csv_file, skiprows=1, header=None, names=col_names) # print(df.head(3)) # print(df.tail(3)) sql_template = ''' INSERT INTO level%02d ( trading_date, security_id, numof_holders, numof_stocks, percentof_stocks ) VALUES (?,?,?,?,?); ''' affected = -1 for index, row in dfrm.iterrows(): sql = sql_template % row['level'] try: db_conn.execute(sql, ( iso_date, row['security_id'], row['numof_holders'], row['numof_stocks'], row['percentof_stocks'] )) if index > 0 and index % 5000 == 0: logger.debug('已儲存 TDCC %s 的股權分散資料 %d 筆', iso_date, index) affected = index except sqlite3.IntegrityError: affected = 0 break if affected > 0: logger.info('已匯入 TDCC %s 的股權分散資料 %d 筆', iso_date, affected) else: logger.warning('已匯入過 TDCC %s 的股權分散資料', iso_date) db_conn.commit() db_conn.close() def rebuild_dist(): """ 重建股權分散表資料庫 """ # 清除現有資料 db_conn = get_connection() for level in range(1, 18): sql = 'DELETE FROM level%02d;' % level db_conn.execute(sql) db_conn.commit() db_conn.execute('VACUUM') # cannot VACUUM from within a transaction db_conn.close() # 確認可以重建的日期 csv_dir = common.get_cache_dir('tdcc') date_list = [] for filename in os.listdir(csv_dir): match = re.match(r'dist-(\d{8}).csv.xz', filename) if match is not None: date_list.append(match.group(1)) # 依日期順序重建資料 date_list.sort() for csv_date in date_list: import_dist(csv_date) def backup_dist(refresh=False): """ 備份最新的股權分散表 """ url = 'https://smart.tdcc.com.tw/opendata/getOD.ashx' params = { 'id': '1-5' } def hook(resp): logger = common.get_logger('finance') # 確認統計日期 csv = resp.text dt_beg = csv.find('\n') + 1 dt_end = csv.find(',', dt_beg) csv_date = csv[dt_beg:dt_end] date_cache = DateCache('tdcc', 'dist', 'csv') changed = refresh or not date_cache.has(csv_date) # 製作備份檔 if changed: date_cache.save(csv_date, csv) logger.info('已更新 TDCC %s 的股權分散表', csv_date) else: logger.info('已存在 TDCC %s 的股權分散表, 不需更新', csv_date) return changed return fucking_get(hook, url, params) def sync_dataset(): """ 暫時寫成這個形式方便排程用 """ changed = backup_dist() if changed: import_dist() # 測試時,即使快取存在也重新匯入一次 # backup_dist() # import_dist() def main(): """ 下載最新的股權分散表,轉檔到資料庫: python3 -m twnews.finance.tdcc 使用既有的 CSV 檔案重建股權分散表資料庫: python3 -m twnews.finance.tdcc rebuild """ action = get_argument(1, 'update') logger = common.get_logger('finance') if action == 'update': sync_dataset() elif action == 'rebuild': rebuild_dist() else: logger.error('無法識別的動作 %s', action) if __name__ == '__main__': main() ================================================ FILE: twnews/finance/ticksmap.py ================================================ # pylint: disable=all import io import json import os import re import requests import sys import subprocess from datetime import datetime import wx import wx.xrc from bs4 import BeautifulSoup from twnews.cache import DateCache class CaptchaDialog(wx.App): """ 驗證碼詢問 GUI """ def __init__(self, captcha_stream): self.captcha_code = False self.captcha_stream = captcha_stream super().__init__(self) def OnInit(self): """ 載入 GUI 與 Enter 事件配置 """ try: path = os.path.realpath(os.path.dirname(__file__) + '/../res/ticksmap-captcha.xrc') res = wx.xrc.XmlResource(path) self.frame = res.LoadFrame(None, 'main_frame') cpi = wx.xrc.XRCCTRL(self.frame, 'captcha_image', 'wxStaticBitmap') im = wx.Image(self.captcha_stream) bm = wx.Bitmap(im) cpi.SetBitmap(bm) self.cpc = wx.xrc.XRCCTRL(self.frame, 'captcha_code', 'wxTextCtrl') self.cpc.Bind(wx.EVT_KEY_UP, self.OnKeyPress, id=wx.xrc.XRCID('captcha_code')) self.frame.Centre() self.frame.Show() except: return False return True def OnKeyPress(self, event): """ 文字輸入框按下 Enter 後送出 """ if event.GetKeyCode() == 13: self.captcha_code = self.cpc.GetValue() self.frame.Close() def handle_captcha(captcha_stream): """ 用 wxPython 介面詢問驗證碼 """ app = CaptchaDialog(captcha_stream) app.MainLoop() return app.captcha_code def load_soup(security_id, date_str): """ 分點進出 HTML 載入作業,含快取管理與下載流程 TODO: 加強錯誤處理 """ dc = DateCache('bsr.twse', security_id, 'html') # 偵測快取 if date_str != 'latest': if dc.has(date_str): soup = BeautifulSoup(dc.load(date_str), 'lxml') return soup return None # 無快取狀況下載分點進出網頁 session = requests.Session() resp = session.get('https://bsr.twse.com.tw/bshtm/bsMenu.aspx') if resp.status_code != 200: return None soup = BeautifulSoup(resp.text, 'lxml') nodes = soup.select('form input') params = {} for node in nodes: name = node.attrs['name'] # 忽略鉅額交易的 radio button if name in ('RadioButton_Excd', 'Button_Reset'): continue if 'value' in node.attrs: params[node.attrs['name']] = node.attrs['value'] else: params[node.attrs['name']] = '' # 找 captcha 圖片 captcha_image = soup.select('#Panel_bshtm img')[0]['src'] m = re.search(r'guid=(.+)', captcha_image) if m is None: return None # 顯示 captcha 圖片 url = 'https://bsr.twse.com.tw/bshtm/' + captcha_image resp = requests.get(url) if resp.status_code != 200: return None captcha_stream = io.BytesIO(resp.content) captcha_code = handle_captcha(captcha_stream) if captcha_code == False: return None params['CaptchaControl1'] = captcha_code params['TextBox_Stkno'] = security_id # 送出 resp = session.post('https://bsr.twse.com.tw/bshtm/bsMenu.aspx', data=params) if resp.status_code != 200: print('任務失敗: %d' % resp.status_code) return None soup = BeautifulSoup(resp.text, 'lxml') nodes = soup.select('#HyperLink_DownloadCSV') if len(nodes) == 0: print('任務失敗,沒有下載連結') return None # 下載分點進出 CSV # 分點進出 CSV 沒有日期 # HTML https://bsr.twse.com.tw/bshtm/bsContent.aspx?v=t (其實任意參數都是 HTML) # CSV https://bsr.twse.com.tw/bshtm/bsContent.aspx url = 'https://bsr.twse.com.tw/bshtm/bsContent.aspx?v=t' resp = session.get(url) if resp.status_code != 200: print('任務失敗,無法下載分點進出 CSV') return None # 拆解分點進出網頁,找日期欄,然後存入快取 soup = BeautifulSoup(resp.text, 'lxml') root_tables = soup.select('#sp_HtmlCode > table') # 取日期資訊,製作快取檔 # TODO: 簡化與容錯處理 meta_path = 'tr > td > table > tr:nth-of-type(1) > td > table' meta_table = root_tables[0].select(meta_path)[0] date_item = meta_table.select('#receive_date')[0] date_str = date_item.get_text().strip().replace('/', '') dc.save(date_str, resp.text) return soup def parse_tick_node(row): """ 撮合值的 td 取出 (分點 ID, 買量, 賣量) """ cols = row.select('td') rank = cols[0].get_text().strip() if rank == '': return (False, False, False) loc_id = cols[1].get_text().strip()[0:4] bid_vol = int(cols[3].get_text().strip().replace(',', '')) ask_vol = int(cols[4].get_text().strip().replace(',', '')) return (loc_id, bid_vol, ask_vol) def main(): """ 分點進出表下載工具 """ if len(sys.argv) < 2: exit(1) if len(sys.argv) == 3: datestr = sys.argv[2] else: datestr = 'latest' print('* 載入分點進出明細', flush=True) soup = load_soup(sys.argv[1], datestr) if soup is None: exit(1) # 取最頂層的表格,數目應該是頁數的 2 倍 # * 偶數表是 meta data 與 detail # * 奇數表是 pagination print('* 製作熱值圖 HTML', flush=True) root_tables = soup.select('#sp_HtmlCode > table') meta_path = 'tr > td > table > tr:nth-of-type(1) > td > table' meta_table = root_tables[0].select(meta_path)[0] trading_date = meta_table.select('#receive_date')[0] \ .get_text() \ .strip() \ .replace('/', '-') (security_id, security_name) = meta_table.select('#stock_id')[0] \ .get_text() \ .strip() \ .split('\xa0') # 注意這裡是 ascii 160,   不能使用一般空白字元切 # 處理根層級的偶數表,蒐集撮合紀錄 tick_nodes = [] for even in range(0, len(root_tables), 2): # 偶數表中取撮合紀錄表,左表奇數次交易,右表偶數次交易 sel = '#table2 > tr > td > table' ticks_table = root_tables[even].select(sel) even_ticks = ticks_table[0].select('tr') odd_ticks = ticks_table[1].select('tr') i = 1 while i < len(even_ticks): tick_nodes.append(even_ticks[i]) tick_nodes.append(odd_ticks[i]) i += 1 # 分點買賣明細加總 volsum = {} for tick_node in tick_nodes: (loc_id, bid, ask) = parse_tick_node(tick_node) if loc_id != False: if loc_id not in volsum: volsum[loc_id] = { 'bid': bid, 'ask': ask } else: volsum[loc_id]['bid'] += bid volsum[loc_id]['ask'] += ask # 置入 geojson path = os.path.realpath(os.path.dirname(__file__) + '/../res/ticksmap-locations.geojson') with open(path, 'r') as ffc: fc = json.load(ffc) filtered_features = [] for feature in fc['features']: loc_id = feature['properties']['id'] if loc_id in volsum: feature['properties']['bid'] = volsum[loc_id]['bid'] feature['properties']['ask'] = volsum[loc_id]['ask'] filtered_features.append(feature) fc['features'] = filtered_features # 置入 heatmap 模板 path = os.path.realpath(os.path.dirname(__file__) + '/../res/ticksmap-template.html') with open(path, 'r') as tplf: leaflet = os.path.expanduser('~/Desktop/ticksmap-{}-{}.html'.format( security_id, trading_date.replace('-', '') )) screenshot = os.path.expanduser('~/Desktop/ticksmap-{}-{}.png'.format( security_id, trading_date.replace('-', '') )) # 將分點進出資料套版,生成 leaflet 熱值圖網頁 fcstr = json.dumps(fc) template = tplf.read() template = template.replace('__FEATURE_COLLECTION__', fcstr, 1) template = template.replace('__SECURITY_ID__', security_id, 1) template = template.replace('__SECURITY_NAME__', security_name, 1) html = template.replace('__DATE__', trading_date, 1) with open(leaflet, 'w') as out: out.write(html) # 用 headless browser 將 leaflet 網頁轉換成圖檔 # TODO: 自動偵測瀏覽器路徑 # * Windows 使用者 Chrome # * Windows 系統 Chrome # * Windows Brave # * Chrome for MacOS chrome_bin = '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser' # chrome_bin = r'C:\Program Files (x86)\BraveSoftware\Brave-Browser\Application\brave.exe' # ok! # 相關參數參考 https://peter.sh/experiments/chromium-command-line-switches/ cmd = [ chrome_bin, '--headless', '--hide-scrollbars', '--window-size=1000x850', '--screenshot=' + screenshot, leaflet ] print('* 製作熱值圖 PNG', flush=True) subprocess.run(cmd, stderr=subprocess.DEVNULL) # 用預設軟體開啟圖檔 # MacOS: open # Windows + PS: start-process -file # print(os.path.realpath(screenshot)) # cmd = [ 'powershell', 'start-process', '-file', os.path.realpath(screenshot) ] cmd = [ 'open', os.path.realpath(screenshot) ] # print(cmd) subprocess.run(cmd) if __name__ == '__main__': main() ================================================ FILE: twnews/finance/tpex.py ================================================ """ 櫃買中心資料蒐集模組 """ from datetime import datetime import io import re import sqlite3 import sys import time import pandas import twnews.common as common from twnews.finance import get_argument, fucking_get, get_connection, REPEAT_LIMIT, REPEAT_INTERVAL from twnews.cache import DateCache from twnews.exceptions import InvalidDataException, NetworkException URL_BASE = 'https://www.tpex.org.tw/web/stock/' def download_margin(datestr): """ 下載信用交易資料集 """ url = URL_BASE + 'margin_trading/margin_balance/margin_bal_result.php' params = { 'd': datestr, 'l': 'zh_tw', 'o': 'json' } def hook(resp): dataset = resp.json() if dataset['iTotalRecords'] == 0: raise InvalidDataException('日期格式錯誤,或是 %s 的資料尚未產出' % datestr) return dataset return fucking_get(hook, url, params) def download_block(datestr): """ 下載鉅額交易資料集 """ url = URL_BASE + 'block_trade/daily_qutoes/block_day_download.php' params = { 'd': datestr, 'l': 'zh_tw', 's': '0,asc,0', 'charset': 'UTF-8' } def hook(resp): # TODO: 需要檢查資料完整性,任意日期都有資料 dataset = resp.text return dataset return fucking_get(hook, url, params) def download_institution(datestr): """ 下載三大法人資料集 """ url = URL_BASE + '3insti/daily_trade/3itrade_hedge_result.php' params = { 'd': datestr, 'l': 'zh_tw', 'o': 'json', 's': '0,asc', 't': 'D', 'se': 'EW' } def hook(resp): dataset = resp.json() # 取標題內日期,轉換成與輸入參數相同的格式 title = dataset['reportTitle'] date_in_title = re.sub('[年月]', '/', title[:title.find(' ') - 1]) # 參數日期與標題日期相同才視為有效資料 if datestr != date_in_title: raise InvalidDataException('日期格式錯誤,或是 %s 的資料尚未產出' % datestr) return dataset return fucking_get(hook, url, params) def download_selled(datestr): """ 下載已借券賣出 """ url = URL_BASE + 'margin_trading/margin_sbl/margin_sbl_download.php' params = { 'd': datestr, 'l': 'zh-tw', 's': '0,asc,0', 'charset': 'utf-8' } def hook(resp): # TODO: 非交易日還是有資料,不過只有 header 和 footer obuf = io.StringIO() ibuf = io.StringIO(resp.text) # 過濾 header, footer & 欄位名稱消除空白字元 enabled = False line = ibuf.readline() while line: if not enabled: enabled = line.startswith('股票代號') if enabled: line = line.replace(' ', '') else: enabled = line.startswith('"') if enabled: obuf.write(line) line = ibuf.readline() dataset = obuf.getvalue() ibuf.close() obuf.close() return dataset return fucking_get(hook, url, params) def import_margin(dbcon, trading_date, dataset): """ 匯入信用交易資料集 """ sql = ''' INSERT INTO `margin` ( trading_date, security_id, security_name, buying_balance, selling_balance ) VALUES (?,?,?,?,?) ''' for detail in dataset['aaData']: # TODO security_id = detail[0] security_name = detail[1].strip() buying_balance = int(detail[6].replace(',', '')) selling_balance = int(detail[14].replace(',', '')) dbcon.execute(sql, ( trading_date, security_id, security_name, buying_balance, selling_balance )) def import_block(dbcon, trading_date, dataset): """ 匯入鉅額交易資料集 """ col_names = ['交易型態', '交割期別', '代號', '名稱', '成交價格(元)', '成交股數', '成交值(元)', '成交時間'] # Pandas 只能吃 file-like 參數,需要把 dataset 轉成 StringIO dfrm = pandas.read_csv( io.StringIO(dataset), engine='python', sep=',', skiprows=3, skipfooter=1, names=col_names ) sql = ''' INSERT INTO `block` ( trading_date, security_id, security_name, tick_rank, tick_type, close, volume, total ) VALUES (?,?,?,?,?,?,?,?) ''' tick_rank = {} for _index, row in dfrm.iterrows(): security_id = row['代號'] security_name = row['名稱'] tick_type = row['交易型態'] close = float(row['成交價格(元)']) volume = int(row['成交股數'].replace(',', '')) total = int(row['成交值(元)'].replace(',', '')) if security_id not in tick_rank: tick_rank[security_id] = 1 else: tick_rank[security_id] += 1 dbcon.execute(sql, ( trading_date, security_id, security_name, tick_rank[security_id], tick_type, close, volume, total )) def import_institution(dbcon, trading_date, dataset): """ 匯入三大法人資料集 """ sql = ''' INSERT INTO `institution` ( trading_date, security_id, security_name, foreign_trend, stic_trend, dealer_trend ) VALUES (?,?,?,?,?,?) ''' for detail in dataset['aaData']: security_id = detail[0] security_name = detail[1].strip() # 外資 + 外資自營 + 陸資 foreign_trend = int(detail[10].replace(',', '')) // 1000 # 投信 stic_trend = int(detail[13].replace(',', '')) // 1000 # 自營投資 + 自營避險 dealer_trend = int(detail[22].replace(',', '')) // 1000 dbcon.execute(sql, ( trading_date, security_id, security_name, foreign_trend, stic_trend, dealer_trend )) def import_selled(dbcon, trading_date, dataset): """ 匯入借券賣出 """ sql = ''' UPDATE `short_sell` SET `security_name`=?,`selled`=? WHERE `trading_date`=? AND `security_id`=? ''' dfrm = pandas.read_csv(io.StringIO(dataset), sep=',') for _, row in dfrm.iterrows(): security_id = row['股票代號'] security_name = row['股票名稱'].strip() balance = int(row['借券賣出當日餘額'].replace(',', '')) dbcon.execute(sql, (security_name, balance, trading_date, security_id)) def sync_dataset(dsitem, trading_date='latest'): """ 同步資料集共用流程 * HTTP 日期格式: 108/05/29 * DB, Cache 日期格式: 2019-05-29 """ if trading_date == 'latest': trading_date = datetime.today().strftime('%Y-%m-%d') logger = common.get_logger('finance') dtm = re.match(r'(\d{4})-(\d{2})-(\d{2})', trading_date) tokens = [ str(int(dtm.group(1)) - 1911), dtm.group(2), dtm.group(3) ] datestr = '/'.join(tokens) data_format = 'csv' if dsitem in ['block', 'selled'] else 'json' this_mod = sys.modules[__name__] daily_cache = DateCache('tpex', dsitem, data_format) if daily_cache.has(trading_date): # 載入快取資料集 logger.info('套用 TPEX %s 的 %s 快取', trading_date, dsitem) dataset = daily_cache.load(trading_date) else: # 下載資料集 dataset = None repeat = 0 hookfunc = getattr(this_mod, 'download_' + dsitem) while dataset is None and repeat < REPEAT_LIMIT: repeat += 1 if repeat > 1: time.sleep(REPEAT_INTERVAL) try: logger.info('下載 TPEX %s 的 %s', trading_date, dsitem) dataset = hookfunc(datestr) logger.debug('儲存 TPEX %s 的 %s', trading_date, dsitem) daily_cache.save(trading_date, dataset) except InvalidDataException as ex: logger.error( '無法取得 TPEX %s 的 %s (重試: %d, %s)', trading_date, dsitem, repeat, ex.reason ) repeat = REPEAT_LIMIT except NetworkException as ex: logger.error( '無法取得 TPEX %s 的 %s (重試: %d, %s)', trading_date, dsitem, repeat, ex.reason ) if dataset is None: return # return # 匯入資料庫 # pylint: disable=bare-except dbcon = get_connection() hookfunc = getattr(this_mod, 'import_' + dsitem) try: hookfunc(dbcon, trading_date, dataset) logger.info('匯入 TPEX %s 的 %s', trading_date, dsitem) except sqlite3.IntegrityError as ex: logger.warning('已經匯入過 TPEX %s 的 %s', trading_date, dsitem) except: logger.error('無法匯入 TPEX %s 的 %s', trading_date, dsitem) dbcon.commit() dbcon.close() def main(): """ python3 -m twnews.finance.tpex {action} python3 -m twnews.finance.tpex {action} {date} """ action = get_argument(1) trading_date = get_argument(2, 'latest') if trading_date != 'latest' and re.match(r'^\d{4}-\d{2}-\d{2}$', trading_date) is None: print('日期格式錯誤') return if action in ['block', 'margin', 'institution', 'selled']: sync_dataset(action, trading_date) else: print('參數錯誤') if __name__ == '__main__': main() ================================================ FILE: twnews/finance/twse.py ================================================ """ 證交所資料蒐集模組 """ from datetime import datetime import io import re import sqlite3 import sys import time import pandas import twnews.common as common from twnews.finance import get_argument, fucking_get, get_connection, REPEAT_LIMIT, REPEAT_INTERVAL from twnews.cache import DateCache from twnews.exceptions import NetworkException, InvalidDataException def download_margin(datestr): """ 下載信用交易資料集 """ url = 'http://www.twse.com.tw/exchangeReport/MI_MARGN' params = { 'date': datestr, 'response': 'json', 'selectType': 'ALL' } def hook(resp): dataset = resp.json() status = dataset['stat'] if status == 'OK': if not dataset['data']: raise InvalidDataException('可能尚未結算或是非交易日') else: raise NetworkException(status) return dataset return fucking_get(hook, url, params) def download_block(datestr): """ 下載鉅額交易資料集 """ url = 'http://www.twse.com.tw/block/BFIAUU' params = { 'date': datestr, 'response': 'json', 'selectType': 'S' } def hook(resp): dataset = resp.json() status = dataset['stat'] if status == 'OK': if not dataset['data']: raise InvalidDataException('可能尚未結算或是非交易日') else: raise NetworkException(status) return dataset return fucking_get(hook, url, params) def download_institution(datestr): """ 下載三大法人資料集 """ url = 'http://www.twse.com.tw/fund/T86' params = { 'date': datestr, 'response': 'json', 'selectType': 'ALL' } def hook(resp): # TODO: 需要驗證資料完整性 dataset = resp.json() status = dataset['stat'] if status != 'OK': raise NetworkException(status) return dataset return fucking_get(hook, url, params) def download_borrowed(datestr): """ 下載可借券賣出資料集 (只有當天資料) TODO: 待確認資料切換時間 """ url = 'http://www.twse.com.tw/SBL/TWT96U' params = { 'response': 'csv' } def hook(resp): dataset = resp.text line1 = dataset[:dataset.find('\r\n')] match = re.search(r'(\d{3})年(\d{2})月(\d{2})日', line1) if match is not None: dtup = ( int(match.group(1)) + 1911, match.group(2), match.group(3) ) dsdate = '%04d%s%s' % dtup if dsdate != datestr: raise InvalidDataException('資料日期 %s 與指定日期不同' % dsdate) else: raise NetworkException('無法取得 CSV 內的日期字串') return dataset return fucking_get(hook, url, params) def download_selled(datestr): """ 下載已借券賣出 """ url = 'http://www.twse.com.tw/exchangeReport/TWT93U' params = { 'date': datestr, 'response': 'json' } def hook(resp): dataset = resp.json() status = dataset['stat'] if status == 'OK': if not dataset['data']: raise InvalidDataException('可能尚未結算或非交易日') else: raise NetworkException(status) return dataset return fucking_get(hook, url, params) def download_etfnet(datestr): """ 下載 ETF 淨值折溢價率 """ url = 'https://mis.twse.com.tw/stock/data/all_etf.txt' params = {} def hook(resp): dataset = resp.json() dsdate = dataset['a1'][1]['msgArray'][0]['i'] if datestr != dsdate: raise InvalidDataException('資料日期 %s 與指定日期不同' % dsdate) return dataset return fucking_get(hook, url, params) def import_margin(dbcon, trading_date, dataset): """ 匯入信用交易資料集 """ sql = ''' INSERT INTO `margin` ( trading_date, security_id, security_name, buying_balance, selling_balance ) VALUES (?,?,?,?,?) ''' for detail in dataset['data']: security_id = detail[0] security_name = detail[1].strip() buying_balance = int(detail[6].replace(',', '')) selling_balance = int(detail[12].replace(',', '')) dbcon.execute(sql, ( trading_date, security_id, security_name, buying_balance, selling_balance )) def import_block(dbcon, trading_date, dataset): """ 匯入鉅額交易資料集 """ sql = ''' INSERT INTO `block` ( trading_date, security_id, security_name, tick_rank, tick_type, close, volume, total ) VALUES (?,?,?,?,?,?,?,?) ''' tick_rank = {} for trade in dataset['data']: if trade[0] == '總計': break security_id = trade[0] security_name = trade[1] tick_type = trade[2] close = float(trade[3].replace(',', '')) volume = int(trade[4].replace(',', '')) total = int(trade[5].replace(',', '')) if security_id not in tick_rank: tick_rank[security_id] = 1 else: tick_rank[security_id] += 1 dbcon.execute(sql, ( trading_date, security_id, security_name, tick_rank[security_id], tick_type, close, volume, total )) def import_institution(dbcon, trading_date, dataset): """ 匯入三大法人資料集 """ sql = ''' INSERT INTO `institution` ( trading_date, security_id, security_name, foreign_trend, stic_trend, dealer_trend ) VALUES (?,?,?,?,?,?) ''' for detail in dataset['data']: security_id = detail[0] security_name = detail[1].strip() foreign_trend = int(detail[4].replace(',', '')) // 1000 stic_trend = int(detail[10].replace(',', '')) // 1000 dealer_trend = int(detail[11].replace(',', '')) // 1000 dbcon.execute(sql, ( trading_date, security_id, security_name, foreign_trend, stic_trend, dealer_trend )) def import_borrowed(dbcon, trading_date, dataset): """ 匯入可借券賣出資料集 (使用 pandas 處理 CSV) """ sql = ''' INSERT INTO `short_sell` ( trading_date, security_id, borrowed ) VALUES (?,?,?) ''' col_names = ['sec1', 'vol1', 'sec2', 'vol2', 'shit'] # Pandas 只能吃 file-like 參數,需要把 dataset 轉成 StringIO dfrm = pandas.read_csv(io.StringIO(dataset), sep=',', skiprows=3, header=None, names=col_names) cnt = 0 for _, row in dfrm.iterrows(): # 匯入左側資料 security_id = row['sec1'].strip('="') borrowed = int(row['vol1'].replace(',', '')) dbcon.execute(sql, (trading_date, security_id, borrowed)) cnt += 1 # 匯入右側資料 security_id = row['sec2'].strip('="') if security_id != '_': borrowed = int(row['vol2'].replace(',', '')) dbcon.execute(sql, (trading_date, security_id, borrowed)) cnt += 1 def import_selled(dbcon, trading_date, dataset): """ 匯入已借券賣出資料集 """ sql = ''' UPDATE `short_sell` SET `security_name`=?, `selled`=? WHERE `trading_date`=? AND `security_id`=? ''' for detail in dataset['data']: security_id = detail[0] security_name = detail[1].strip() balance = int(detail[12].replace(',', '')) if security_id != '': # TODO: 如果 WHERE 條件不成立,沒更新到資料,應該要產生 Exception 觸發錯誤回報 dbcon.execute(sql, ( security_name, balance, trading_date, security_id )) def import_etfnet(dbcon, trading_date, dataset): """ 匯入 ETF 淨值折溢價率 """ # 來源資料轉換 key/value 形式 # 相同發行者的 ETF 會放一組 etf_dict = {} for fund in dataset['a1']: if 'msgArray' in fund: for etf in fund['msgArray']: etf_dict[etf['a']] = etf # 依證券代碼順序處理 sql = ''' INSERT INTO `etf_offset` ( trading_date, security_id, security_name, close, net, offset ) VALUES (?,?,?,?,?,?) ''' for k in sorted(etf_dict.keys()): etf = etf_dict[k] dbcon.execute(sql, (trading_date, etf['a'], etf['b'], etf['e'], etf['f'], etf['g'])) def sync_dataset(dsitem, trading_date='latest'): """ 同步資料集共用流程 """ if trading_date == 'latest': trading_date = datetime.today().strftime('%Y-%m-%d') logger = common.get_logger('finance') datestr = trading_date.replace('-', '') data_format = 'csv' if dsitem == 'borrowed' else 'json' this_mod = sys.modules[__name__] daily_cache = DateCache('twse', dsitem, data_format) if daily_cache.has(datestr): # 載入快取資料集 logger.debug('套用 TWSE %s 的 %s 快取', trading_date, dsitem) dataset = daily_cache.load(datestr) else: # 下載資料集 dataset = None repeat = 0 hookfunc = getattr(this_mod, 'download_' + dsitem) while dataset is None and repeat < REPEAT_LIMIT: repeat += 1 if repeat > 1: time.sleep(REPEAT_INTERVAL) try: logger.info('下載 TWSE %s 的 %s', trading_date, dsitem) dataset = hookfunc(datestr) logger.debug('儲存 TWSE %s 的 %s', trading_date, dsitem) daily_cache.save(datestr, dataset) except InvalidDataException as ex: logger.error( '無法取得 TWSE %s 的 %s (重試: %d, %s)', trading_date, dsitem, repeat, ex.reason ) repeat = REPEAT_LIMIT except NetworkException as ex: logger.error( '無法取得 TWSE %s 的 %s (重試: %d, %s)', trading_date, dsitem, repeat, ex.reason ) if dataset is None: return # 匯入資料庫 # pylint: disable=bare-except dbcon = get_connection() hookfunc = getattr(this_mod, 'import_' + dsitem) try: hookfunc(dbcon, trading_date, dataset) logger.info('匯入 TWSE %s 的 %s', trading_date, dsitem) except sqlite3.IntegrityError as ex: logger.warning('已經匯入過 TWSE %s 的 %s', trading_date, dsitem) except: # TODO: ex.args[0] 不確定是否可靠, 需要再確認 logger.error('無法匯入 TWSE %s 的 %s', trading_date, dsitem) dbcon.commit() dbcon.close() def main(): """ python3 -m twnews.finance.twse {action} python3 -m twnews.finance.twse {action} {date} """ action = get_argument(1) trading_date = get_argument(2, 'latest') if trading_date != 'latest' and re.match(r'^\d{4}-\d{2}-\d{2}$', trading_date) is None: print('日期格式錯誤') return if action in ['block', 'margin', 'institution', 'borrowed', 'selled', 'etfnet']: sync_dataset(action, trading_date) else: print('參數錯誤') if __name__ == '__main__': main() ================================================ FILE: twnews/res/ticksmap-captcha.xrc ================================================ 輸入驗證碼 wxVERTICAL 230,160 200,15 wxALIGN_CENTER 200,60 200,15 wxALIGN_CENTER 200,25 200,15 wxALIGN_CENTER 200,30 ================================================ FILE: twnews/res/ticksmap-locations.geojson ================================================ { "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55632732452477, 25.04158688504074 ] }, "properties": { "id": "1020", "name": "\u5408\u5eab", "phone": "02-27319987" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51080823591725, 25.043664306140116 ] }, "properties": { "id": "1030", "name": "\u571f\u9280", "phone": "02-23483948" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51310710381462, 25.043913459588925 ] }, "properties": { "id": "1040", "name": "\u81fa\u9280\u8b49\u5238", "phone": "02-23882188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51028779488004, 25.051170155854706 ] }, "properties": { "id": "1110", "name": "\u53f0\u7063\u4f01\u9280", "phone": "02-25597171" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53342667008538, 25.052281416537795 ] }, "properties": { "id": "1160", "name": "\u65e5\u76db", "phone": "02-25048888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51167945998723, 25.042175310370748 ] }, "properties": { "id": "1230", "name": "\u5f70\u9280", "phone": "02-23619654" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55309086689374, 25.03297338266213 ] }, "properties": { "id": "1260", "name": "\u5b8f\u9060", "phone": "02-27008899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54368267948932, 25.047179768694402 ] }, "properties": { "id": "1360", "name": "\u6e2f\u5546\u9ea5\u683c\u7406", "phone": "02-27347500" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54931009689535, 25.029235814800124 ] }, "properties": { "id": "1380", "name": "\u53f0\u7063\u532f\u7acb", "phone": "02-2326-8188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54925496369476, 25.02601029425199 ] }, "properties": { "id": "1440", "name": "\u7f8e\u6797", "phone": "02-23763766" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54925496369476, 25.02601029425199 ] }, "properties": { "id": "1470", "name": "\u53f0\u7063\u6469\u6839\u58eb\u4e39\u5229", "phone": "02-27302888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54925496369476, 25.02601029425199 ] }, "properties": { "id": "1480", "name": "\u7f8e\u5546\u9ad8\u76db", "phone": "02-27304000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54517955306842, 25.058078123771878 ] }, "properties": { "id": "1520", "name": "\u745e\u58eb\u4fe1\u8cb8", "phone": "02-27156388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55371954979228, 25.037410864660483 ] }, "properties": { "id": "1530", "name": "\u6e2f\u5546\u5fb7\u610f\u5fd7", "phone": "02-21922888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56608187757948, 25.03877471028857 ] }, "properties": { "id": "1560", "name": "\u6e2f\u5546\u91ce\u6751", "phone": "02-21769999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56669383519447, 25.04064778336209 ] }, "properties": { "id": "1570", "name": "\u6e2f\u5546\u6cd5\u570b\u8208\u696d", "phone": "02-21750800" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56608187757948, 25.03877471028857 ] }, "properties": { "id": "1590", "name": "\u82b1\u65d7\u74b0\u7403", "phone": "8726-9000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5688646287331, 25.03826461521507 ] }, "properties": { "id": "1650", "name": "\u65b0\u52a0\u5761\u5546\u745e\u9280", "phone": "02-87227200" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51309587724606, 25.043075555632672 ] }, "properties": { "id": "2180", "name": "\u4e9e\u6771", "phone": "02-23618600" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54367316718195, 25.05204949387523 ] }, "properties": { "id": "2200", "name": "\u5143\u5927\u671f\u8ca8", "phone": "02-27176000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54918468731599, 25.028912522276457 ] }, "properties": { "id": "2210", "name": "\u7fa4\u76ca\u671f\u8ca8", "phone": "02-2700-2888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51706465414371, 25.050152610866082 ] }, "properties": { "id": "5050", "name": "\u5927\u5c55", "phone": "02-25551234" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54614850573897, 25.051999380423336 ] }, "properties": { "id": "5110", "name": "\u5bcc\u9686", "phone": "02-27182788" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53568958854905, 25.057707199312865 ] }, "properties": { "id": "5260", "name": "\u5927\u6176", "phone": "02-25084888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.22860157863632, 24.955210757911725 ] }, "properties": { "id": "5320", "name": "\u9ad8\u6a4b", "phone": "03-4224243" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52468602293277, 25.04876928202976 ] }, "properties": { "id": "5380", "name": "\u7b2c\u4e00\u91d1", "phone": "02-25636262" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.6888876522262, 24.163771451198038 ] }, "properties": { "id": "5460", "name": "\u5bf6\u76db", "phone": "04-22309377" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51701086522118, 25.032492670595666 ] }, "properties": { "id": "5600", "name": "\u6c38\u8208", "phone": "02-23218200" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.82198887585135, 24.56031630372757 ] }, "properties": { "id": "5660", "name": "\u65e5\u9032", "phone": "037-332266" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56518798473458, 25.050297600264386 ] }, "properties": { "id": "5850", "name": "\u7d71\u4e00", "phone": "02-27478266" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30056660961714, 22.634887195832352 ] }, "properties": { "id": "5860", "name": "\u76c8\u6ea2", "phone": "07-2888516" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.6107618870506, 23.976696137468185 ] }, "properties": { "id": "5870", "name": "\u5149\u9686", "phone": "038-352181" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54394897702572, 25.039444340340598 ] }, "properties": { "id": "5920", "name": "\u5143\u5bcc", "phone": "02-23255818" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.6818310173108, 23.976856378820973 ] }, "properties": { "id": "5960", "name": "\u65e5\u8302", "phone": "049-2353266" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54427997732583, 25.05284928794247 ] }, "properties": { "id": "6010", "name": "\u7287\u4e9e\u8b49\u5238", "phone": "02-27180101" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68151648556015, 24.13779326319005 ] }, "properties": { "id": "6110", "name": "\u53f0\u4e2d\u9280", "phone": "04-22268588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.61617924984901, 25.0589172348979 ] }, "properties": { "id": "6160", "name": "\u4e2d\u570b\u4fe1\u8a17", "phone": "02-66392000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29800724636863, 22.623099703721376 ] }, "properties": { "id": "6210", "name": "\u65b0\u767e\u738b", "phone": "07-2118888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.5242747909776, 23.87335182058557 ] }, "properties": { "id": "6380", "name": "\u5149\u548c", "phone": "04-8886500" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.30300040827895, 24.993786703883426 ] }, "properties": { "id": "6450", "name": "\u6c38\u5168", "phone": "03-3352155" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.45795929347729, 25.008461659152243 ] }, "properties": { "id": "6460", "name": "\u5927\u660c", "phone": "02-29689685" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.518143901973, 25.045820830940887 ] }, "properties": { "id": "6480", "name": "\u798f\u90a6", "phone": "02-23836888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.30631297712581, 24.992110225995972 ] }, "properties": { "id": "6620", "name": "\u5168\u6cf0", "phone": "03-3353359" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53258288735728, 25.04201384619974 ] }, "properties": { "id": "6910", "name": "\u5fb7\u4fe1", "phone": "02-23939988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.44149706381457, 25.1694911587292 ] }, "properties": { "id": "6950", "name": "\u798f\u52dd", "phone": "02-26251818" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53098268243339, 25.043042093948422 ] }, "properties": { "id": "7000", "name": "\u5146\u8c50", "phone": "02-23278988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20167088614014, 22.99998813402813 ] }, "properties": { "id": "7030", "name": "\u81f4\u548c", "phone": "06-2219777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.72673628232234, 24.25488700661086 ] }, "properties": { "id": "7070", "name": "\u8c50\u8fb2", "phone": "04-25281000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.20649400143107, 24.952791292516785 ] }, "properties": { "id": "7080", "name": "\u77f3\u6a4b", "phone": "03-4927373" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.3247967662418, 22.620387790266808 ] }, "properties": { "id": "7670", "name": "\u91d1\u6e2f", "phone": "07-7253922" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5152164425769, 25.012069955709205 ] }, "properties": { "id": "7750", "name": "\u5317\u57ce", "phone": "02-29283456" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51396094014368, 25.06958687115064 ] }, "properties": { "id": "7790", "name": "\u570b\u7968", "phone": "02-25288988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52250680552487, 25.055200268481965 ] }, "properties": { "id": "8150", "name": "\u53f0\u65b0", "phone": "02-2181-5888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.32446616282999, 22.58870591508886 ] }, "properties": { "id": "8380", "name": "\u5b89\u6cf0", "phone": "07-8122789" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56677327562443, 25.032587487648936 ] }, "properties": { "id": "8440", "name": "\u6469\u6839\u5927\u901a", "phone": "02-87862288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56521045118325, 25.04281373711842 ] }, "properties": { "id": "8450", "name": "\u5eb7\u548c", "phone": "02-87871888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.44447000080147, 23.475370003551532 ] }, "properties": { "id": "8490", "name": "\u842c\u6cf0", "phone": "05-2289911" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.5375320581055, 24.259971290645026 ] }, "properties": { "id": "8520", "name": "\u4e2d\u8fb2", "phone": "04-26572801" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51309791903128, 25.043609091008246 ] }, "properties": { "id": "8560", "name": "\u65b0\u5149", "phone": "02-23118181" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53511049086421, 25.052216677516075 ] }, "properties": { "id": "8580", "name": "\u806f\u90a6\u5546\u9280", "phone": "02-25040066" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56413596337005, 25.059200351508807 ] }, "properties": { "id": "8710", "name": "\u967d\u4fe1", "phone": "02-27629288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5584161, 25.0330058 ] }, "properties": { "id": "8770", "name": "\u5927\u9f0e", "phone": "02-87862666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5476906789493, 25.057382833887658 ] }, "properties": { "id": "8840", "name": "\u7389\u5c71", "phone": "02-27131313" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54912154770592, 25.02199616910617 ] }, "properties": { "id": "8880", "name": "\u570b\u6cf0", "phone": "02-23269888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56354738285579, 25.04027198666496 ] }, "properties": { "id": "8890", "name": "\u5927\u548c\u570b\u6cf0", "phone": "02-27239698" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56460399421985, 25.033524181174343 ] }, "properties": { "id": "8900", "name": "\u6cd5\u9280\u5df4\u9ece", "phone": "02-87297000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56111164490846, 25.03425396521133 ] }, "properties": { "id": "8960", "name": "\u9999\u6e2f\u4e0a\u6d77\u532f\u8c50", "phone": "02-66312899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5476906789493, 25.057382833887658 ] }, "properties": { "id": "9100", "name": "\u7fa4\u76ca\u91d1\u9f0e", "phone": "02-87898888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55150597524369, 25.084875603296265 ] }, "properties": { "id": "9200", "name": "\u51f1\u57fa", "phone": "02-21818888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55091534806718, 25.05773398758345 ] }, "properties": { "id": "9300", "name": "\u83ef\u5357\u6c38\u660c", "phone": "02-25456888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55228341974629, 25.038171253374973 ] }, "properties": { "id": "9600", "name": "\u5bcc\u90a6", "phone": "02-87716888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54367316718195, 25.05204949387523 ] }, "properties": { "id": "9800", "name": "\u5143\u5927", "phone": "02-27177777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51313466224889, 25.046858563293043 ] }, "properties": { "id": "9A00", "name": "\u6c38\u8c50\u91d1", "phone": "02-2311-4345" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.67932882032501, 24.138023049092705 ] }, "properties": { "id": "1021", "name": "\u5408\u5eab- \u53f0\u4e2d", "phone": "04-22255141" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20785217188497, 22.998048342742422 ] }, "properties": { "id": "1022", "name": "\u5408\u5eab-\u53f0\u5357", "phone": "06-2260148" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.28415335084445, 22.624858545156123 ] }, "properties": { "id": "1023", "name": "\u5408\u5eab-\u9ad8\u96c4", "phone": "07-5319755" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.44830999896347, 23.480500006287315 ] }, "properties": { "id": "1024", "name": "\u5408\u5eab-\u5609\u7fa9", "phone": "05-2220016" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.74243480777429, 25.129790883787546 ] }, "properties": { "id": "1025", "name": "\u5408\u5eab-\u57fa\u9686", "phone": "02-24288468" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54226127991265, 24.08201552308815 ] }, "properties": { "id": "1028", "name": "\u5408\u5eab - \u5f70\u5316", "phone": "04-7295528" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.36076902006839, 22.63198133614876 ] }, "properties": { "id": "1029", "name": "\u5408\u5eab - \u9cf3\u5c71", "phone": "07-7905555" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.97270020694022, 24.804291620951954 ] }, "properties": { "id": "102A", "name": "\u5408\u5eab-\u65b0\u7af9", "phone": "03-5262711" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53180372709332, 25.052251466892706 ] }, "properties": { "id": "102C", "name": "\u5408\u5eab-\u81ea\u5f37", "phone": "02-25218815" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.31150586549468, 24.991279043189472 ] }, "properties": { "id": "102E", "name": "\u5408\u5eab-\u6843\u5712", "phone": "03-347-3456" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.66157747025434, 24.165313145938327 ] }, "properties": { "id": "102F", "name": "\u5408\u5eab-\u897f\u53f0\u4e2d", "phone": "04-2316-6368" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49800733486221, 25.06144447654486 ] }, "properties": { "id": "102G", "name": "\u5408\u5eab-\u4e09\u91cd", "phone": "02-2977-9588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54533682918803, 25.04842521151739 ] }, "properties": { "id": "102Q", "name": "\u5408\u5eab-\u570b\u969b\u8b49\u5238", "phone": "02-27319987" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.67990128465617, 24.13825322494037 ] }, "properties": { "id": "1031", "name": "\u571f\u9280-\u53f0\u4e2d", "phone": "04-22266845" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20339440181245, 22.992252120248214 ] }, "properties": { "id": "1032", "name": "\u571f\u9280-\u53f0\u5357", "phone": "06-2200558" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.27129411775813, 22.873571988641256 ] }, "properties": { "id": "1033", "name": "\u571f\u9280-\u9ad8\u96c4", "phone": "07-5319591" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.44979999686525, 23.47966000124929 ] }, "properties": { "id": "1034", "name": "\u571f\u9280-\u5609\u7fa9", "phone": "05-2224930" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.96659466996886, 24.80375868702233 ] }, "properties": { "id": "1035", "name": "\u571f\u9280-\u65b0\u7af9", "phone": "03-5213211" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.31489456142324, 23.3332966299898 ] }, "properties": { "id": "1036", "name": "\u571f\u9280-\u7389\u91cc", "phone": "03-8884900" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.60528118307762, 23.98263045084194 ] }, "properties": { "id": "1037", "name": "\u571f\u9280-\u82b1\u84ee", "phone": "038-330723" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5474650234814, 25.024833568124606 ] }, "properties": { "id": "1038", "name": "\u571f\u9280-\u548c\u5e73", "phone": "02-27001555" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52724587319906, 25.097343788113815 ] }, "properties": { "id": "1039", "name": "\u571f\u9280-\u58eb\u6797", "phone": "02-28323842" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.3164644400523, 22.635521544152244 ] }, "properties": { "id": "103A", "name": "\u571f\u9280-\u5efa\u570b", "phone": "07-2224911" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54183356049035, 24.080770728752796 ] }, "properties": { "id": "103B", "name": "\u571f\u9280-\u5f70\u5316", "phone": "04-7201777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.414848991017, 23.351634208408967 ] }, "properties": { "id": "103C", "name": "\u571f\u9280-\u767d\u6cb3", "phone": "06-6852888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.60640542181336, 25.05446942001287 ] }, "properties": { "id": "103F", "name": "\u571f\u9280-\u5357\u6e2f", "phone": "02-26539955" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.35732650742509, 22.629326183169592 ] }, "properties": { "id": "1041", "name": "\u81fa\u9280-\u9cf3\u5c71", "phone": "07-7452126" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.19675565514052, 22.99330465321226 ] }, "properties": { "id": "1042", "name": "\u81fa\u9280-\u81fa\u5357", "phone": "06-2202507" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51851236194777, 25.062495687748147 ] }, "properties": { "id": "1043", "name": "\u81fa\u9280-\u6c11\u6b0a", "phone": "02-25529458" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.9702534128656, 24.80177054430763 ] }, "properties": { "id": "1045", "name": "\u81fa\u9280-\u65b0\u7af9", "phone": "03-5266799" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.6204925306737, 24.34941595522094 ] }, "properties": { "id": "104A", "name": "\u81fa\u9280-\u81fa\u4e2d", "phone": "04-22238370" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29537003211789, 22.61962931052201 ] }, "properties": { "id": "104C", "name": "\u81fa\u9280-\u9ad8\u96c4", "phone": "07-2711434" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52639082254834, 25.028249598276087 ] }, "properties": { "id": "104D", "name": "\u81fa\u9280-\u91d1\u5c71", "phone": "02-23418678" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.67896972188629, 24.143131876821887 ] }, "properties": { "id": "1111", "name": "\u53f0\u7063\u4f01\u9280-\u53f0\u4e2d", "phone": "04-2270160" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.19802574994664, 22.99270074166405 ] }, "properties": { "id": "1112", "name": "\u53f0\u7063\u4f01\u9280-\u53f0\u5357", "phone": "06-2238967" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30653312289412, 22.64079219600887 ] }, "properties": { "id": "1113", "name": "\u53f0\u7063\u4f01\u9280-\u4e5d\u5982", "phone": "07-3137171" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.45106999990244, 23.479200007141184 ] }, "properties": { "id": "1114", "name": "\u53f0\u7063\u4f01\u9280-\u5609\u7fa9", "phone": "05-2278043" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.7178125, 24.1301842 ] }, "properties": { "id": "1115", "name": "\u53f0\u7063\u4f01\u9280-\u592a\u5e73", "phone": "04-22757802" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.489969232361, 22.670347729445268 ] }, "properties": { "id": "1116", "name": "\u53f0\u7063\u4f01\u9280-\u5c4f\u6771", "phone": "08-7327171" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.00969324648646, 24.826725088982517 ] }, "properties": { "id": "1117", "name": "\u53f0\u7063\u4f01\u9280-\u7af9\u5317", "phone": "03-5527171" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.71535072688161, 24.251532446909962 ] }, "properties": { "id": "1118", "name": "\u53f0\u7063\u4f01\u9280-\u8c50\u539f", "phone": "04-25253485" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29587875997149, 22.795320846840365 ] }, "properties": { "id": "1119", "name": "\u53f0\u7063\u4f01\u9280-\u5ca1\u5c71", "phone": "07-6227171" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.43975670187386, 23.52144527714178 ] }, "properties": { "id": "111A", "name": "\u53f0\u7063\u4f01\u9280-\u6c11\u96c4", "phone": "05-2207171" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5184056211577, 25.0529491430657 ] }, "properties": { "id": "111B", "name": "\u53f0\u7063\u4f01\u9280-\u5efa\u6210", "phone": "02-25506998" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30159407232479, 22.632742219225428 ] }, "properties": { "id": "111C", "name": "\u53f0\u7063\u4f01\u9280-\u4e09\u6c11", "phone": "07-2877171" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51309704441478, 25.043398910926587 ] }, "properties": { "id": "111D", "name": "\u81fa\u7063\u4f01\u9280-\u53f0\u5317", "phone": "02-23880971" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.19929070410133, 25.06746781989051 ] }, "properties": { "id": "111E", "name": "\u81fa\u7063\u4f01\u9280-\u6843\u5712", "phone": "03-3311007" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30872276956832, 22.63465156760871 ] }, "properties": { "id": "111F", "name": "\u53f0\u7063\u4f01\u9280-\u5317\u9ad8\u96c4", "phone": "07-2360116" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.47399617905653, 25.015708971866616 ] }, "properties": { "id": "111G", "name": "\u81fa\u7063\u4f01\u9280-\u57d4\u5898", "phone": "02-89515671" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51313594465451, 25.046588077225692 ] }, "properties": { "id": "1161", "name": "\u65e5\u76db-\u5fe0\u5b5d", "phone": "02-23117676" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.211231212601, 22.998331684858304 ] }, "properties": { "id": "1162", "name": "\u65e5\u76db-\u53f0\u5357", "phone": "06-2208088" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.65802322556158, 24.157501330064473 ] }, "properties": { "id": "1163", "name": "\u65e5\u76db-\u53f0\u4e2d", "phone": "04-23278989" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.58702324772196, 25.06885851523333 ] }, "properties": { "id": "1164", "name": "\u65e5\u76db-\u5167\u6e56", "phone": "02-87927888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.45884157473422, 25.008598217597026 ] }, "properties": { "id": "1165", "name": "\u65e5\u76db-\u677f\u6a4b", "phone": "02-29693333" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.510193268056, 25.001498418233083 ] }, "properties": { "id": "1166", "name": "\u65e5\u76db-\u96d9\u548c", "phone": "02-29206868" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.43782999882556, 23.46793000485439 ] }, "properties": { "id": "1167", "name": "\u65e5\u76db-\u5609\u7fa9", "phone": "05-2860777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29160481593269, 22.631515517996363 ] }, "properties": { "id": "1168", "name": "\u65e5\u76db-\u9ad8\u96c4", "phone": "07-2816888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52582340111636, 25.092753962167233 ] }, "properties": { "id": "1169", "name": "\u65e5\u76db-\u58eb\u6797", "phone": "02-28831515" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56731982932799, 24.98833379889497 ] }, "properties": { "id": "116A", "name": "\u65e5\u76db-\u6728\u67f5", "phone": "02-22342616" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.2251226719558, 24.957608037965695 ] }, "properties": { "id": "116B", "name": "\u65e5\u76db-\u4e2d\u58e2", "phone": "03-4273888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.29970803171479, 24.95993352049299 ] }, "properties": { "id": "116C", "name": "\u65e5\u76db-\u516b\u5fb7", "phone": "03-3622888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49804393990259, 25.062408436133325 ] }, "properties": { "id": "116E", "name": "\u65e5\u76db-\u4e09\u91cd", "phone": "02-29845858" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.5707048949148, 23.957347491571056 ] }, "properties": { "id": "116F", "name": "\u65e5\u76db-\u54e1\u6797", "phone": "04-8326118" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54063427936396, 24.991821165066195 ] }, "properties": { "id": "116G", "name": "\u65e5\u76db-\u666f\u7f8e", "phone": "02-9353966" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.97270020694022, 24.804291620951954 ] }, "properties": { "id": "116H", "name": "\u65e5\u76db-\u65b0\u7af9", "phone": "03-5227868" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52944637920923, 25.051881061427295 ] }, "properties": { "id": "116I", "name": "\u65e5\u76db-\u5357\u4eac", "phone": "02-25215678" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.47906797537641, 25.019361137984383 ] }, "properties": { "id": "116J", "name": "\u65e5\u76db-\u677f\u6a4b\u4e2d\u5c71", "phone": "02-29559000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.60888846070146, 23.977371477505788 ] }, "properties": { "id": "116K", "name": "\u65e5\u76db-\u82b1\u84ee", "phone": "038-346888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.64954856076642, 24.15305289496997 ] }, "properties": { "id": "116L", "name": "\u65e5\u76db-\u5927\u58a9", "phone": "04-23288898" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.48957035317076, 22.675317402185232 ] }, "properties": { "id": "116M", "name": "\u65e5\u76db-\u5c4f\u6771", "phone": "08-7663888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.2337621228569, 22.998759871949794 ] }, "properties": { "id": "116N", "name": "\u65e5\u76db-\u6c38\u5eb7", "phone": "06-3113888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55725922914377, 25.028875092781018 ] }, "properties": { "id": "116P", "name": "\u65e5\u76db-\u4fe1\u7fa9", "phone": "02-27390369" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.36746868801708, 23.89997613328988 ] }, "properties": { "id": "116Q", "name": "\u65e5\u76db-\u4e8c\u6797", "phone": "04-8951808" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.4460097674286, 25.034632171027447 ] }, "properties": { "id": "116S", "name": "\u65e5\u76db-\u65b0\u838a", "phone": "02-22019789" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.2022110994658, 24.96883782461372 ] }, "properties": { "id": "116U", "name": "\u65e5\u76db-\u6843\u5712", "phone": "03-3553188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54105159248628, 23.70872990093559 ] }, "properties": { "id": "116V", "name": "\u65e5\u76db-\u6597\u516d", "phone": "05-5351010" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.3623775474523, 22.625268942966677 ] }, "properties": { "id": "116W", "name": "\u65e5\u76db-\u9cf3\u5c71", "phone": "07-7462488" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.75337274685407, 24.761014320229368 ] }, "properties": { "id": "116X", "name": "\u65e5\u76db-\u5b9c\u862d", "phone": "039-313588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5001116224282, 25.001599923068472 ] }, "properties": { "id": "116Z", "name": "\u65e5\u76db-\u4e2d\u548c", "phone": "02-22493366" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.99475736353257, 24.801203341946138 ] }, "properties": { "id": "116b", "name": "\u65e5\u76db-\u5712\u5340", "phone": "03-5717666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.71972816217485, 24.253464932865967 ] }, "properties": { "id": "116c", "name": "\u65e5\u76db-\u8c50\u539f", "phone": "(04)25229688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.37227801178788, 24.935912457393407 ] }, "properties": { "id": "116d", "name": "\u65e5\u76db-\u4e09\u5cfd", "phone": "02-26745568" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.01920664134106, 24.83387110944215 ] }, "properties": { "id": "116e", "name": "\u65e5\u76db-\u7af9\u5317", "phone": "03-5585988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54422854381538, 25.05047535925724 ] }, "properties": { "id": "116f", "name": "\u65e5\u76db-\u5fa9\u8208", "phone": "02-87718888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.21607720943548, 24.87067940488312 ] }, "properties": { "id": "116g", "name": "\u65e5\u76db-\u9f8d\u6f6d", "phone": "03-4802000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.42308778712945, 24.991153315140735 ] }, "properties": { "id": "116i", "name": "\u65e5\u76db-\u6a39\u6797", "phone": "02-26869968" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.9074091385529, 24.685669888167702 ] }, "properties": { "id": "116j", "name": "\u65e5\u76db-\u982d\u4efd", "phone": "037-663888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29503071447735, 22.6681474940093 ] }, "properties": { "id": "116k", "name": "\u65e5\u76db-\u5317\u9ad8\u96c4", "phone": "07-5501768" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.49992112043795, 24.11062777812132 ] }, "properties": { "id": "116m", "name": "\u65e5\u76db-\u548c\u7f8e", "phone": "04-7565988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.47125800045569, 25.027392998861323 ] }, "properties": { "id": "116r", "name": "\u65e5\u76db-\u6587\u5316", "phone": "02-22569999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.44161556510949, 24.974302992121746 ] }, "properties": { "id": "116s", "name": "\u65e5\u76db-\u571f\u57ce", "phone": "02-82613366" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53342667008538, 25.052281416537795 ] }, "properties": { "id": "116x", "name": "\u65e5\u76db-\u570b\u969b\u8b49\u5238", "phone": "25615888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30649233569413, 22.63455164010488 ] }, "properties": { "id": "1232", "name": "\u5f70\u9280-\u4e03\u8ce2", "phone": "07-2355658" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.66208752306628, 24.121981890403184 ] }, "properties": { "id": "1233", "name": "\u5f70\u9280-\u53f0\u4e2d", "phone": "04-22660011" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56476131199557, 25.05958175606323 ] }, "properties": { "id": "1261", "name": "\u5b8f\u9060-\u6c11\u751f", "phone": "02-27657933" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.20264341500024, 24.967683409334388 ] }, "properties": { "id": "1262", "name": "\u5b8f\u9060-\u6843\u5712", "phone": "03-3463456" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20273029005736, 22.99233203740094 ] }, "properties": { "id": "126D", "name": "\u5b8f\u9060-\u53f0\u5357", "phone": "06-2236677" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.48291408703106, 25.00131097700671 ] }, "properties": { "id": "126H", "name": "\u5b8f\u9060-\u4e2d\u548c", "phone": "02-32346738" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.64630481795642, 24.15414050969535 ] }, "properties": { "id": "126L", "name": "\u5b8f\u9060-\u53f0\u4e2d", "phone": "04-2255-6687" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.31371491262017, 22.630301980875437 ] }, "properties": { "id": "126Q", "name": "\u5b8f\u9060-\u9ad8\u96c4", "phone": "07-2299788" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51136020869055, 25.04467234443559 ] }, "properties": { "id": "126U", "name": "\u5b8f\u9060-\u9928\u524d", "phone": "02-23121122" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30845491756992, 23.03593096673082 ] }, "properties": { "id": "126X", "name": "\u5b8f\u9060-\u65b0\u5316", "phone": "03-5102233" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.45108742668148, 24.995064535148288 ] }, "properties": { "id": "2181", "name": "\u4e9e\u6771-\u677f\u6a4b", "phone": "02-89665558" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.01286162348, 24.7852175964651 ] }, "properties": { "id": "2184", "name": "\u4e9e\u6771-\u65b0\u7af9", "phone": "03-5641818" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.22162554325557, 22.985519366879632 ] }, "properties": { "id": "2185", "name": "\u4e9e\u6771-\u53f0\u5357", "phone": "06-2358999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30512137628241, 22.61333762243996 ] }, "properties": { "id": "2186", "name": "\u4e9e\u6771-\u9ad8\u96c4", "phone": "07-5369888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68375742175336, 24.141871905883995 ] }, "properties": { "id": "2187", "name": "\u4e9e\u6771-\u53f0\u4e2d", "phone": "04-22218600" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51309587724606, 25.043075555632672 ] }, "properties": { "id": "218A", "name": "\u4e9e\u6771-\u570b\u969b\u8b49\u5238", "phone": "23618600" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20402113257764, 23.00375477914528 ] }, "properties": { "id": "5058", "name": "\u5927\u5c55-\u53f0\u5357", "phone": "06-2208866" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52367473697689, 25.049246066329747 ] }, "properties": { "id": "5112", "name": "\u5bcc\u9686-\u9577\u5b89", "phone": "02-25631168" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.47547887366542, 25.081490869215976 ] }, "properties": { "id": "5261", "name": "\u5927\u6176-\u8606\u6d32", "phone": "02-22897766" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.14713887966792, 24.907989183750434 ] }, "properties": { "id": "5262", "name": "\u5927\u6176-\u694a\u6885", "phone": "03-4759977" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.43273544806505, 25.06140485790723 ] }, "properties": { "id": "5263", "name": "\u5927\u6176-\u6cf0\u5c71", "phone": "02-22966688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29995803297672, 22.6180418487384 ] }, "properties": { "id": "5264", "name": "\u5927\u6176-\u9ad8\u96c4", "phone": "07-3312288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.82395733068195, 24.565902960893695 ] }, "properties": { "id": "5265", "name": "\u5927\u6176-\u82d7\u6817", "phone": "037-262888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.20665210622606, 24.956619656393652 ] }, "properties": { "id": "5266", "name": "\u5927\u6176-\u4e2d\u58e2", "phone": "03-4912588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.7452648092833, 25.131951261037777 ] }, "properties": { "id": "5267", "name": "\u5927\u6176-\u57fa\u9686", "phone": "02-24281122" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.19654067148683, 23.001448188353876 ] }, "properties": { "id": "5268", "name": "\u5927\u6176-\u53f0\u5357", "phone": "06-2232233" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68565611605638, 24.171121900936875 ] }, "properties": { "id": "5269", "name": "\u5927\u6176-\u53f0\u4e2d", "phone": "04-22375888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51192366259788, 24.990736483988634 ] }, "properties": { "id": "526A", "name": "\u5927\u6176-\u4e2d\u548c", "phone": "02-89411188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49748640397175, 25.067048077165925 ] }, "properties": { "id": "526K", "name": "\u5927\u6176-\u5bcc\u9806", "phone": "02-29818889" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.46148067540592, 25.084623639808186 ] }, "properties": { "id": "526L", "name": "\u5927\u6176-\u9577\u69ae", "phone": "02-82828289" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.21744862230926, 24.859226111192125 ] }, "properties": { "id": "5321", "name": "\u9ad8\u6a4b-\u9f8d\u6f6d", "phone": "03-4807889" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.2229708455698, 24.957053320201805 ] }, "properties": { "id": "5322", "name": "\u9ad8\u6a4b-\u4e2d\u58e2", "phone": "03-4270889" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.25635682087655, 24.973402789288105 ] }, "properties": { "id": "5323", "name": "\u9ad8\u6a4b-\u5167\u58e2", "phone": "03-4351010" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.57982188951588, 23.96310714236305 ] }, "properties": { "id": "5381", "name": "\u7b2c\u4e00\u91d1-\u54e1\u6797", "phone": "04-8339000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.66367629618756, 24.146974902856645 ] }, "properties": { "id": "5382", "name": "\u7b2c\u4e00\u91d1-\u53f0\u4e2d", "phone": "04-23103648" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.33264111605224, 22.628160096230733 ] }, "properties": { "id": "5383", "name": "\u7b2c\u4e00\u91d1-\u9ad8\u96c4", "phone": "07-7262378" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.21105304066558, 22.98608682149472 ] }, "properties": { "id": "5384", "name": "\u7b2c\u4e00\u91d1-\u53f0\u5357", "phone": "06-2148111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.3096701383553, 24.990159572682227 ] }, "properties": { "id": "5385", "name": "\u7b2c\u4e00\u91d1-\u6843\u5712", "phone": "03-3382881" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.5405651754382, 24.07991419788888 ] }, "properties": { "id": "5386", "name": "\u7b2c\u4e00\u91d1-\u5f70\u5316", "phone": "(04)7203198" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 119.57033061946137, 23.571230163094583 ] }, "properties": { "id": "5387", "name": "\u7b2c\u4e00\u91d1-\u6f8e\u6e56", "phone": "06-9278666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52296967520775, 25.05609341160331 ] }, "properties": { "id": "5389", "name": "\u7b2c\u4e00\u91d1-\u4e2d\u5c71", "phone": "02-25671189" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.301049060845, 22.630861500141197 ] }, "properties": { "id": "538A", "name": "\u7b2c\u4e00\u91d1-\u65b0\u8208", "phone": "07-2516101" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.96768570251307, 24.80669268558839 ] }, "properties": { "id": "538B", "name": "\u7b2c\u4e00\u91d1-\u65b0\u7af9", "phone": "03-5235211" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55767088468362, 25.048853140268008 ] }, "properties": { "id": "538C", "name": "\u7b2c\u4e00\u91d1-\u5149\u5fa9", "phone": "02-25795811" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52945016705947, 25.043041080868733 ] }, "properties": { "id": "538D", "name": "\u7b2c\u4e00\u91d1-\u5fe0\u5b5d", "phone": "02-23214955" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.67941007679012, 24.137141443315237 ] }, "properties": { "id": "538E", "name": "\u7b2c\u4e00\u91d1-\u81ea\u7531", "phone": "04-22287111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51010124220501, 25.055779048032953 ] }, "properties": { "id": "538F", "name": "\u7b2c\u4e00\u91d1-\u5927\u7a3b\u57d5", "phone": "02-25582211" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.90821439331947, 24.68529131931432 ] }, "properties": { "id": "538I", "name": "\u7b2c\u4e00\u91d1-\u982d\u4efd", "phone": "037-596611" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.45017000166573, 23.479750007340233 ] }, "properties": { "id": "538M", "name": "\u7b2c\u4e00\u91d1-\u5609\u7fa9", "phone": "05-2788878" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.71529145466393, 24.247328236929214 ] }, "properties": { "id": "538N", "name": "\u7b2c\u4e00\u91d1-\u8c50\u539f", "phone": "04-25239911" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.2615269366758, 22.854429619530332 ] }, "properties": { "id": "538P", "name": "\u7b2c\u4e00\u91d1-\u8def\u7af9", "phone": "07-6970111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.46630608881111, 25.020666819271213 ] }, "properties": { "id": "538W", "name": "\u7b2c\u4e00\u91d1-\u83ef\u6c5f", "phone": "02-2258-3311" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.21754882154698, 24.958226632489062 ] }, "properties": { "id": "538Y", "name": "\u7b2c\u4e00\u91d1-\u4e2d\u58e2", "phone": "034-922011" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52468602293277, 25.04876928202976 ] }, "properties": { "id": "538a", "name": "\u7b2c\u4e00\u91d1-\u570b\u969b\u8b49\u5238", "phone": "02-2563-6262" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55037249971772, 25.03916965220332 ] }, "properties": { "id": "538j", "name": "\u7b2c\u4e00\u91d1-\u5b89\u548c", "phone": "02-2741-3434" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.66606411995748, 24.182597372968758 ] }, "properties": { "id": "5602", "name": "\u6c38\u8208-\u6c34\u6e73", "phone": "04-22973456" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68766386917704, 24.156206984358093 ] }, "properties": { "id": "5603", "name": "\u6c38\u8208-\u53f0\u4e2d", "phone": "04-22371188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.6499740636171, 24.153990118017944 ] }, "properties": { "id": "5604", "name": "\u6c38\u8208-\u5927\u58a9", "phone": "04-23105858" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30843266758355, 22.630586336239986 ] }, "properties": { "id": "5851", "name": "\u7d71\u4e00-\u9ad8\u96c4", "phone": "07-2268999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5491449680107, 25.03079052738642 ] }, "properties": { "id": "5852", "name": "\u7d71\u4e00-\u6566\u5357", "phone": "02-27552288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.22611013017158, 24.95836005150879 ] }, "properties": { "id": "5853", "name": "\u7d71\u4e00-\u4e2d\u58e2", "phone": "03-4224888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5113748248139, 25.0445453590945 ] }, "properties": { "id": "5854", "name": "\u7d71\u4e00-\u57ce\u4e2d", "phone": "02-23115757" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20803778898836, 22.99416965279709 ] }, "properties": { "id": "5855", "name": "\u7d71\u4e00-\u53f0\u5357", "phone": "06-2112288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.65602950177998, 24.139819802746224 ] }, "properties": { "id": "5856", "name": "\u7d71\u4e00-\u53f0\u4e2d", "phone": "04-23723333" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.96284029055191, 24.80630694155966 ] }, "properties": { "id": "5857", "name": "\u7d71\u4e00-\u65b0\u7af9", "phone": "03-5225666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.4480299975134, 23.48380000163256 ] }, "properties": { "id": "5858", "name": "\u7d71\u4e00-\u5609\u7fa9", "phone": "05-2252111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.49094267229353, 22.677037090104193 ] }, "properties": { "id": "5859", "name": "\u7d71\u4e00-\u5c4f\u6771", "phone": "08-7353888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.7445297465677, 25.1278701320495 ] }, "properties": { "id": "585A", "name": "\u7d71\u4e00-\u57fa\u9686", "phone": "02-24225288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5141227069662, 25.007710804274666 ] }, "properties": { "id": "585B", "name": "\u7d71\u4e00-\u6c38\u548c", "phone": "02-22319966" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.64728349472716, 24.159600946745172 ] }, "properties": { "id": "585D", "name": "\u7d71\u4e00-\u65b0\u53f0\u4e2d", "phone": "04-22587222" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.318693397859, 23.305070418254225 ] }, "properties": { "id": "585E", "name": "\u7d71\u4e00-\u65b0\u71df", "phone": "06-6356388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54221552012775, 24.074378410532198 ] }, "properties": { "id": "585F", "name": "\u7d71\u4e00-\u5f70\u5316", "phone": "04-7225161" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.31114203803266, 24.99250801518787 ] }, "properties": { "id": "585H", "name": "\u7d71\u4e00-\u6843\u5712", "phone": "03-3386677" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.57260691933438, 23.96279503143313 ] }, "properties": { "id": "585I", "name": "\u7d71\u4e00-\u54e1\u6797", "phone": "04-8336288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.48875779593065, 25.05775427791121 ] }, "properties": { "id": "585J", "name": "\u7d71\u4e00-\u4e09\u91cd", "phone": "02-29779933" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.71732082168771, 24.253133197172986 ] }, "properties": { "id": "585L", "name": "\u7d71\u4e00-\u8c50\u539f", "phone": "04-25282211" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52362679934251, 25.082777458086326 ] }, "properties": { "id": "585M", "name": "\u7d71\u4e00-\u58eb\u6797", "phone": "02-28866677" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.458462760798, 25.00823629928768 ] }, "properties": { "id": "585P", "name": "\u7d71\u4e00-\u677f\u6a4b", "phone": "02-29692299" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30132785104318, 22.616088094991387 ] }, "properties": { "id": "585Q", "name": "\u7d71\u4e00-\u4e09\u591a", "phone": "07-3368568" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.63243481202731, 25.06524023578044 ] }, "properties": { "id": "585R", "name": "\u7d71\u4e00-\u6c50\u6b62", "phone": "02-26935558" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.74549234144074, 24.751012675774025 ] }, "properties": { "id": "585S", "name": "\u7d71\u4e00-\u5b9c\u862d", "phone": "03-9353660" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5445807397667, 25.051642163653675 ] }, "properties": { "id": "585U", "name": "\u7d71\u4e00-\u5357\u4eac", "phone": "02-27317777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5214353103667, 25.026656369565988 ] }, "properties": { "id": "585V", "name": "\u7d71\u4e00-\u53e4\u4ead", "phone": "02-23635678" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 118.3178484150609, 24.436729782995897 ] }, "properties": { "id": "585W", "name": "\u7d71\u4e00-\u91d1\u9580", "phone": "082-320811" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.45205345665632, 24.986093726534595 ] }, "properties": { "id": "585Y", "name": "\u7d71\u4e00-\u571f\u57ce", "phone": "02-82602000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5333538005133, 25.053576447295633 ] }, "properties": { "id": "585Z", "name": "\u7d71\u4e00-\u677e\u6c5f", "phone": "0225165988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.57265476937738, 25.081169476091787 ] }, "properties": { "id": "585b", "name": "\u7d71\u4e00-\u5167\u6e56", "phone": "(02)87525959" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55042434806596, 25.039129835969167 ] }, "properties": { "id": "585c", "name": "\u7d71\u4e00-\u4ec1\u611b", "phone": "02-27726588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.21169611131496, 24.959125265424536 ] }, "properties": { "id": "585g", "name": "\u7d71\u4e00-\u5e73\u93ae", "phone": "03-4910736" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.30669017452284, 25.001877530767384 ] }, "properties": { "id": "585h", "name": "\u7d71\u4e00-\u65b0\u6843\u5712", "phone": "03-3347111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.87380076447349, 24.683529993535753 ] }, "properties": { "id": "585m", "name": "\u7d71\u4e00-\u7af9\u5357", "phone": "037-480666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56518798473458, 25.050297600264386 ] }, "properties": { "id": "585s", "name": "\u7d71\u4e00-\u570b\u969b\u8b49\u5238", "phone": "27478266" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.33514317288999, 22.609331825972085 ] }, "properties": { "id": "5861", "name": "\u76c8\u6ea2-\u7c6c\u5b50\u5167", "phone": "07-7134001" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.32652373322583, 22.726228362884704 ] }, "properties": { "id": "5862", "name": "\u76c8\u6ea2-\u6960\u6893", "phone": "07-3537737" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29659653310074, 22.641895914334505 ] }, "properties": { "id": "5921", "name": "\u5143\u5bcc-\u9ad8\u96c4", "phone": "07-3122822" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54489063494309, 24.979764823886704 ] }, "properties": { "id": "5922", "name": "\u5143\u5bcc-\u65b0\u5e97", "phone": "02-29177888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49804393990259, 25.062408436133325 ] }, "properties": { "id": "5923", "name": "\u5143\u5bcc-\u4e09\u91cd", "phone": "02-29885568" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.6580153257328, 24.139881058387353 ] }, "properties": { "id": "5925", "name": "\u5143\u5bcc-\u53f0\u4e2d", "phone": "04-23759979" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30041199188155, 22.616373105192018 ] }, "properties": { "id": "5926", "name": "\u5143\u5bcc-\u56db\u7dad", "phone": "07-3356677" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.39287604319703, 22.499896350454062 ] }, "properties": { "id": "5927", "name": "\u5143\u5bcc-\u6797\u5712", "phone": "07-6433779" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.44441754685428, 25.043003941830467 ] }, "properties": { "id": "5928", "name": "\u5143\u5bcc-\u65b0\u838a", "phone": "02-29962299" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20250082800038, 22.991245189453743 ] }, "properties": { "id": "5929", "name": "\u5143\u5bcc-\u53f0\u5357", "phone": "06-2219089" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30323287182748, 22.651226683701317 ] }, "properties": { "id": "592A", "name": "\u5143\u5bcc-\u7def\u57ce", "phone": "07-3131123" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5159269861439, 24.99727910076563 ] }, "properties": { "id": "592B", "name": "\u5143\u5bcc-\u6c38\u548c", "phone": "02-29491888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.53771296174024, 22.547081614763652 ] }, "properties": { "id": "592C", "name": "\u5143\u5bcc-\u6f6e\u5dde", "phone": "08-7884930" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.32755680817056, 22.63939848887237 ] }, "properties": { "id": "592D", "name": "\u5143\u5bcc-\u5927\u660c", "phone": "07-3851168" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51706465414371, 25.050152610866082 ] }, "properties": { "id": "592E", "name": "\u5143\u5bcc-\u57ce\u4e2d", "phone": "02-25563636" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.97050880990287, 24.802983770673727 ] }, "properties": { "id": "592G", "name": "\u5143\u5bcc-\u65b0\u7af9", "phone": "03-5258282" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52768081447768, 25.03422114617172 ] }, "properties": { "id": "592H", "name": "\u5143\u5bcc-\u4fe1\u7fa9", "phone": "02-23587778" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.45191992247587, 23.474359997368175 ] }, "properties": { "id": "592I", "name": "\u5143\u5bcc-\u5609\u7fa9", "phone": "05-2257789" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.22659843531933, 24.961207584548774 ] }, "properties": { "id": "592L", "name": "\u5143\u5bcc-\u4e2d\u58e2", "phone": "03-4263888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.53790046452411, 24.08888542968815 ] }, "properties": { "id": "592M", "name": "\u5143\u5bcc-\u5f70\u5316", "phone": "04-7283456" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.43691869369535, 23.709790869398873 ] }, "properties": { "id": "592N", "name": "\u5143\u5bcc-\u864e\u5c3e", "phone": "05-6360389" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29545131210409, 22.796245360775856 ] }, "properties": { "id": "592P", "name": "\u5143\u5bcc-\u540c\u5927", "phone": "07-6225788" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55276426992285, 25.041229969741064 ] }, "properties": { "id": "592Q", "name": "\u5143\u5bcc-\u6566\u5357", "phone": "02-87723988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.74425066265421, 25.12916785351181 ] }, "properties": { "id": "592S", "name": "\u5143\u5bcc-\u57fa\u9686", "phone": "02-24288899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.75570369951343, 24.75911660635974 ] }, "properties": { "id": "592U", "name": "\u5143\u5bcc-\u5b9c\u862d", "phone": "03-9369688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52184900863465, 25.06298120166009 ] }, "properties": { "id": "592V", "name": "\u5143\u5bcc-\u6c11\u6b0a", "phone": "02-25926188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.50403139787177, 25.11766062464127 ] }, "properties": { "id": "592W", "name": "\u5143\u5bcc-\u5409\u5229", "phone": "02-28229090" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68511422210337, 23.97915411925385 ] }, "properties": { "id": "592X", "name": "\u5143\u5bcc-\u8349\u5c6f", "phone": "049-2355888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.96425662378368, 23.966471243905307 ] }, "properties": { "id": "592Y", "name": "\u5143\u5bcc-\u57d4\u91cc", "phone": "049-2900999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.18515659326195, 23.04704155154525 ] }, "properties": { "id": "592Z", "name": "\u5143\u5bcc-\u5b89\u5357", "phone": "06-2453088" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.57730018498874, 25.039411243121716 ] }, "properties": { "id": "592a", "name": "\u5143\u5bcc-\u677e\u5fb7", "phone": "02-27202828" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.46362791292195, 25.011230472201422 ] }, "properties": { "id": "592b", "name": "\u5143\u5bcc-\u677f\u6a4b", "phone": "02-89536888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.82940500423508, 24.25835255145808 ] }, "properties": { "id": "592c", "name": "\u5143\u5bcc-\u70cf\u65e5", "phone": "04-23362288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52377471739418, 25.049447283756848 ] }, "properties": { "id": "592d", "name": "\u5143\u5bcc-\u5ef6\u5e73", "phone": "02-25633399" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52518259487991, 25.023067089710995 ] }, "properties": { "id": "592e", "name": "\u5143\u5bcc-\u53e4\u4ead", "phone": "02-83695288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54918332508203, 25.028809056490203 ] }, "properties": { "id": "592f", "name": "\u5143\u5bcc-\u570b\u969b\u8b49\u5238", "phone": "02-23255818" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.70512925856757, 24.210649134356977 ] }, "properties": { "id": "592g", "name": "\u5143\u5bcc-\u4e2d\u539f", "phone": "04-25326677" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.5764453666912, 24.27085713302822 ] }, "properties": { "id": "592i", "name": "\u5143\u5bcc-\u4e2d\u6e2f", "phone": "04-26222299" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68359789181359, 24.123552375178626 ] }, "properties": { "id": "592l", "name": "\u5143\u5bcc-\u5927\u88d5", "phone": "04-22862688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.19622813533071, 23.00126807718617 ] }, "properties": { "id": "592m", "name": "\u5143\u5bcc-\u6210\u529f", "phone": "06-2232323" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5621392827883, 25.051249042141304 ] }, "properties": { "id": "592n", "name": "\u5143\u5bcc-\u897f\u677e", "phone": "02-27562288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30946136100962, 22.633841960715735 ] }, "properties": { "id": "592o", "name": "\u5143\u5bcc-\u65b0\u8208", "phone": "07-238-5678" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.48946906338843, 22.67502402819757 ] }, "properties": { "id": "592q", "name": "\u5143\u5bcc-\u5c4f\u6771", "phone": "08-7339522" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53372924185965, 25.052227659874184 ] }, "properties": { "id": "592r", "name": "\u5143\u5bcc-\u57ce\u6771", "phone": "02-2509-9928" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.560614272243, 25.032831394583 ] }, "properties": { "id": "592u", "name": "\u5143\u5bcc-\u4e16\u8cbf", "phone": "02-8780-1800" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.31377235397191, 24.993299059018685 ] }, "properties": { "id": "592v", "name": "\u5143\u5bcc-\u6843\u5712", "phone": "03-3366000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.17789962640872, 23.162333499195682 ] }, "properties": { "id": "592w", "name": "\u5143\u5bcc-\u4f73\u91cc", "phone": "06-7232323" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.60855774104839, 23.980962687612802 ] }, "properties": { "id": "592y", "name": "\u5143\u5bcc-\u82b1\u84ee", "phone": "038-360988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.64858793682005, 24.161800336910584 ] }, "properties": { "id": "592z", "name": "\u5143\u5bcc-\u6587\u5fc3", "phone": "04-2252-1010" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.9697332593408, 23.972951168878808 ] }, "properties": { "id": "5961", "name": "\u65e5\u8302-\u57d4\u91cc", "phone": "049-2902266" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68988481133744, 23.904333274183937 ] }, "properties": { "id": "5962", "name": "\u65e5\u8302-\u5357\u6295", "phone": "049-2234188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54427997732583, 25.05284928794247 ] }, "properties": { "id": "6012", "name": "\u7287\u4e9e-\u7db2\u8def", "phone": "02-27188788" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54427997732583, 25.05284928794247 ] }, "properties": { "id": "601d", "name": "\u7287\u4e9e-\u946b\u8c50", "phone": "2553-8000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.57224147519605, 23.958870715562373 ] }, "properties": { "id": "6114", "name": "\u53f0\u4e2d\u9280-\u54e1\u6797", "phone": "04-8329000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52672651320907, 25.044200325643104 ] }, "properties": { "id": "6115", "name": "\u53f0\u4e2d\u9280-\u53f0\u5317", "phone": "02-27736955" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.22349127762543, 24.9596912673925 ] }, "properties": { "id": "6116", "name": "\u53f0\u4e2d\u9280-\u4e2d\u58e2", "phone": "03-4251366" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.71762130435985, 24.251778471274513 ] }, "properties": { "id": "611A", "name": "\u53f0\u4e2d\u9280-\u8c50\u539f", "phone": "04-25274150" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.48653409092897, 25.058489804338667 ] }, "properties": { "id": "6161", "name": "\u4e2d\u570b\u4fe1\u8a17-\u4e09\u91cd", "phone": "02-89822558" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.518143901973, 25.045820830940887 ] }, "properties": { "id": "6162", "name": "\u4e2d\u570b\u4fe1\u8a17-\u5fe0\u5b5d", "phone": "02-23141122" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.23267477345988, 23.010051164550713 ] }, "properties": { "id": "6163", "name": "\u4e2d\u570b\u4fe1\u8a17-\u6c38\u5eb7", "phone": "06-2338233" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.69341807795026, 24.171561129488683 ] }, "properties": { "id": "6164", "name": "\u4e2d\u570b\u4fe1\u8a17-\u6587\u5fc3", "phone": "04-22468800" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.97839373585595, 24.808753319963362 ] }, "properties": { "id": "6165", "name": "\u4e2d\u570b\u4fe1\u8a17-\u65b0\u7af9", "phone": "03-5153100" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53291623074024, 25.05817542340487 ] }, "properties": { "id": "6167", "name": "\u4e2d\u570b\u4fe1\u8a17-\u677e\u6c5f", "phone": "02-2581-5688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.44602999905491, 23.479710004329007 ] }, "properties": { "id": "6168", "name": "\u4e2d\u570b\u4fe1\u8a17-\u5609\u7fa9", "phone": "05-2286699" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.22562001118777, 24.955591426543446 ] }, "properties": { "id": "616A", "name": "\u4e2d\u570b\u4fe1\u8a17-\u4e2d\u58e2", "phone": "03-4229666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29524517582577, 22.62944534371887 ] }, "properties": { "id": "616K", "name": "\u4e2d\u570b\u4fe1\u8a17-\u9ad8\u96c4", "phone": "07-2151166" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.61617924984901, 25.0589172348979 ] }, "properties": { "id": "616X", "name": "\u4e2d\u570b\u4fe1\u8a17-\u570b\u969b\u8b49\u5238", "phone": "02-87891075" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.48102518564805, 23.962144712489064 ] }, "properties": { "id": "6381", "name": "\u5149\u548c-\u6eaa\u6e56", "phone": "04-8855466" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.58649943775725, 23.859545894548138 ] }, "properties": { "id": "6382", "name": "\u5149\u548c-\u7530\u4e2d", "phone": "04-8746588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.50055588592154, 24.109845847192513 ] }, "properties": { "id": "6383", "name": "\u5149\u548c-\u548c\u7f8e", "phone": "04-7567789" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.53743501734364, 24.026014813874514 ] }, "properties": { "id": "6385", "name": "\u5149\u548c-\u82b1\u58c7", "phone": "04-7878288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.43431219554525, 23.71195000626339 ] }, "properties": { "id": "6386", "name": "\u5149\u548c-\u864e\u5c3e", "phone": "05-6366606" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.24478447502852, 23.46550724149527 ] }, "properties": { "id": "638A", "name": "\u5149\u548c-\u5609\u7fa9", "phone": "05-3700988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.29024968219726, 25.044547832062065 ] }, "properties": { "id": "6451", "name": "\u6c38\u5168-\u5357\u5d01", "phone": "03-3529529" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.30097821836128, 24.966308041479497 ] }, "properties": { "id": "6452", "name": "\u6c38\u5168-\u516b\u5fb7", "phone": "03-3771155" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.42266600302548, 24.994424494440416 ] }, "properties": { "id": "6461", "name": "\u5927\u660c-\u6a39\u6797", "phone": "02-26756088" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51704476183637, 24.965246785613697 ] }, "properties": { "id": "6462", "name": "\u5927\u660c-\u5b89\u5eb7", "phone": "02-86669988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.96830137317828, 24.80658844649912 ] }, "properties": { "id": "6463", "name": "\u5927\u660c-\u65b0\u7af9", "phone": "03-5222868" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54307783307529, 24.974149341421573 ] }, "properties": { "id": "6464", "name": "\u5927\u660c-\u65b0\u5e97", "phone": "02-29179111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.30631540665239, 25.015783040929783 ] }, "properties": { "id": "6465", "name": "\u5927\u660c-\u6843\u5712", "phone": "03-3263689" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.0112241075229, 24.82838426545032 ] }, "properties": { "id": "6489", "name": "\u798f\u90a6-\u65b0\u7af9", "phone": "(03)657-2758" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.67421135814217, 24.14780093700684 ] }, "properties": { "id": "6912", "name": "\u5fb7\u4fe1-\u4e2d\u6b63", "phone": "04-22026200" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.31004782243852, 23.30025062788236 ] }, "properties": { "id": "6913", "name": "\u5fb7\u4fe1-\u65b0\u71df", "phone": "06-6337258" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.48653409092897, 25.058489804338667 ] }, "properties": { "id": "6914", "name": "\u5fb7\u4fe1-\u4e09\u91cd", "phone": "02-29718188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55544255681822, 25.033326294536327 ] }, "properties": { "id": "6915", "name": "\u5fb7\u4fe1-\u548c\u5e73", "phone": "02-27066168" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.44863000262052, 23.483660003616816 ] }, "properties": { "id": "7001", "name": "\u5146\u8c50-\u5609\u7fa9", "phone": "05-2230230" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.65602950177998, 24.139819802746224 ] }, "properties": { "id": "7003", "name": "\u5146\u8c50-\u53f0\u4e2d", "phone": "04-23780568" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.55876142541811, 24.23507881851443 ] }, "properties": { "id": "7005", "name": "\u5146\u8c50-\u53f0\u4e2d\u6e2f", "phone": "04-26651100" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20282294141413, 22.991220352244525 ] }, "properties": { "id": "7006", "name": "\u5146\u8c50-\u53f0\u5357", "phone": "06-2230398" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.01810324418457, 24.83446989636906 ] }, "properties": { "id": "7007", "name": "\u5146\u8c50-\u7af9\u5317", "phone": "03-5543223" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49626518131451, 25.068208688513103 ] }, "properties": { "id": "7008", "name": "\u5146\u8c50-\u4e09\u91cd", "phone": "02-29817799" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54148433251433, 24.99304326364308 ] }, "properties": { "id": "7009", "name": "\u5146\u8c50-\u666f\u7f8e", "phone": "02-29307799" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.4671353979285, 25.020903092028107 ] }, "properties": { "id": "700B", "name": "\u5146\u8c50-\u677f\u6a4b", "phone": "02-22538699" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54185822382208, 23.711469651070505 ] }, "properties": { "id": "700C", "name": "\u5146\u8c50-\u4f86\u798f", "phone": "05-5338989" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.46102485524321, 23.79987277506219 ] }, "properties": { "id": "700D", "name": "\u5146\u8c50-\u897f\u87ba", "phone": "05-5867999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.47813203726781, 23.67648786737452 ] }, "properties": { "id": "700E", "name": "\u5146\u8c50-\u6597\u5357", "phone": "05-5968899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.43272165827663, 23.709313224167115 ] }, "properties": { "id": "700F", "name": "\u5146\u8c50-\u864e\u5c3e", "phone": "05-6313388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.2514068608281, 23.183820419872205 ] }, "properties": { "id": "700G", "name": "\u5146\u8c50-\u9ebb\u8c46", "phone": "06-5728388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52725727205754, 25.03284008699618 ] }, "properties": { "id": "700H", "name": "\u5146\u8c50-\u6771\u9580", "phone": "02-23435488" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.2927626709086, 22.628061773337215 ] }, "properties": { "id": "700I", "name": "\u5146\u8c50-\u5317\u9ad8\u96c4", "phone": "07-2612345" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.66416695363438, 24.153887765496673 ] }, "properties": { "id": "700J", "name": "\u5146\u8c50-\u516c\u76ca", "phone": "04-23259966" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.31886080985575, 23.305447062274474 ] }, "properties": { "id": "700K", "name": "\u5146\u8c50-\u65b0\u71df", "phone": "06-6357111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52500393091108, 25.105764576725797 ] }, "properties": { "id": "700L", "name": "\u5146\u8c50-\u5929\u6bcd", "phone": "02-28376006" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.31386087778516, 24.993050052275894 ] }, "properties": { "id": "700M", "name": "\u5146\u8c50-\u6843\u5712", "phone": "033475188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.47906908932586, 25.018974169601893 ] }, "properties": { "id": "700N", "name": "\u5146\u8c50-\u57d4\u5898", "phone": "02-89538888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53838936499712, 25.052168806885454 ] }, "properties": { "id": "700P", "name": "\u5146\u8c50-\u5357\u4eac", "phone": "02-25169888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.35663738406656, 22.5670365332859 ] }, "properties": { "id": "700R", "name": "\u5146\u8c50-\u5c0f\u6e2f", "phone": "07-8063000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51291235673688, 25.056895718821124 ] }, "properties": { "id": "700S", "name": "\u5146\u8c50-\u5927\u540c", "phone": "02-25506078" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.3195445883964, 24.981329774899802 ] }, "properties": { "id": "700U", "name": "\u5146\u8c50-\u6843\u9daf", "phone": "03-3776899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.9673082706535, 24.808101880081118 ] }, "properties": { "id": "700V", "name": "\u5146\u8c50-\u65b0\u7af9", "phone": "03-5256199" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51313466224889, 25.046858563293043 ] }, "properties": { "id": "700W", "name": "\u5146\u8c50-\u57ce\u4e2d", "phone": "02-23315199" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51488449207005, 25.01206120155432 ] }, "properties": { "id": "700X", "name": "\u5146\u8c50-\u6c38\u548c", "phone": "02-2927-3799" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30199103660321, 22.61169290424269 ] }, "properties": { "id": "700Z", "name": "\u5146\u8c50-\u9ad8\u96c4", "phone": "07-3315200" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56401916764547, 25.041454803163717 ] }, "properties": { "id": "700a", "name": "\u5146\u8c50-\u5fe0\u5b5d", "phone": "02-27479966" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.22482517808481, 24.95597498069337 ] }, "properties": { "id": "700b", "name": "\u5146\u8c50-\u4e2d\u58e2", "phone": "03-2807759" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54599656069931, 25.05752194670108 ] }, "properties": { "id": "700c", "name": "\u5146\u8c50-\u6c11\u751f", "phone": "02-27169966" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54018929392772, 24.080244984992184 ] }, "properties": { "id": "700d", "name": "\u5146\u8c50-\u5f70\u5316", "phone": "04-7289966" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.43781865302104, 24.04978775399383 ] }, "properties": { "id": "700f", "name": "\u5146\u8c50-\u9e7f\u6e2f", "phone": "04-7772900" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52133799907199, 25.028901369220723 ] }, "properties": { "id": "700g", "name": "\u5146\u8c50-\u5357\u9580", "phone": "02-23959966" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.32738874138066, 22.6403480578452 ] }, "properties": { "id": "700h", "name": "\u5146\u8c50-\u4e09\u6c11", "phone": "07-3958858" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.57881976097696, 25.04115112795631 ] }, "properties": { "id": "700i", "name": "\u5146\u8c50-\u677e\u5fb7", "phone": "02-27275168" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54248917089005, 25.033164961865154 ] }, "properties": { "id": "700j", "name": "\u5146\u8c50-\u5927\u5b89", "phone": "02-27003236" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.5707048949148, 23.957347491571056 ] }, "properties": { "id": "700k", "name": "\u5146\u8c50-\u54e1\u6797", "phone": "04-8373898" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53098268243339, 25.043042093948422 ] }, "properties": { "id": "700m", "name": "\u5146\u8c50-\u570b\u969b\u8b49\u5238", "phone": "02-23278988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54427997732583, 25.05284928794247 ] }, "properties": { "id": "700p", "name": "\u5146\u8c50-\u5fa9\u8208", "phone": "02-25148588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.59330144601653, 25.083048642448958 ] }, "properties": { "id": "700q", "name": "\u5146\u8c50-\u5167\u6e56", "phone": "02-27946088" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.62380564198072, 24.179341562932603 ] }, "properties": { "id": "700r", "name": "\u5146\u8c50-\u5bf6\u6210", "phone": "(04)24651001" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29924152677988, 22.79389014621156 ] }, "properties": { "id": "700s", "name": "\u5146\u8c50-\u5ca1\u5c71", "phone": "07-6235988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.45959732952268, 25.05310083633913 ] }, "properties": { "id": "700w", "name": "\u5146\u8c50-\u65b0\u838a", "phone": "02-89913777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54783170237387, 25.033089164464428 ] }, "properties": { "id": "7031", "name": "\u81f4\u548c-\u53f0\u5317", "phone": "02-7006666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.17503317026895, 23.159217193865654 ] }, "properties": { "id": "7032", "name": "\u81f4\u548c-\u4f73\u91cc", "phone": "06-7226666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20748712090527, 22.988865663697815 ] }, "properties": { "id": "7033", "name": "\u81f4\u548c-\u5e9c\u524d", "phone": "06-2135888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.19158367324256, 22.979759528475316 ] }, "properties": { "id": "7034", "name": "\u81f4\u548c-\u91d1\u83ef", "phone": "06-2619777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53053748121414, 25.033845482256062 ] }, "properties": { "id": "7035", "name": "\u81f4\u548c-\u6771\u9580", "phone": "02-23516600" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.31537135154954, 22.625269792846776 ] }, "properties": { "id": "7036", "name": "\u81f4\u548c-\u9ad8\u96c4", "phone": "07-2259255" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56374706530237, 25.051212713926915 ] }, "properties": { "id": "7038", "name": "\u81f4\u548c-\u5357\u4eac", "phone": "02-27485558" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.22470732358194, 22.97612845848132 ] }, "properties": { "id": "703B", "name": "\u81f4\u548c-\u5d07\u5fb7", "phone": "06-2899000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.13981783310743, 22.764504101240743 ] }, "properties": { "id": "7791", "name": "\u570b\u7968-\u53f0\u6771", "phone": "089-321789" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49856954246648, 25.131038726484828 ] }, "properties": { "id": "7792", "name": "\u570b\u7968-\u5317\u6295", "phone": "02-28969268" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.60644409499218, 25.055027489790394 ] }, "properties": { "id": "7795", "name": "\u570b\u7968-\u5357\u6e2f", "phone": "02-26535757" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.2928471733345, 22.628089237897047 ] }, "properties": { "id": "7797", "name": "\u570b\u7968-\u4e2d\u6b63", "phone": "07-2166166" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.25826718621055, 24.973711236675197 ] }, "properties": { "id": "7798", "name": "\u570b\u7968-\u5167\u58e2", "phone": "03-4618688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20538701514548, 22.998813941015683 ] }, "properties": { "id": "779D", "name": "\u570b\u7968-\u53f0\u5357", "phone": "06-2203979" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.29171271722683, 25.04763353137008 ] }, "properties": { "id": "779E", "name": "\u570b\u7968-\u5357\u5d01", "phone": "03-3115688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.45211339409485, 25.03682602352376 ] }, "properties": { "id": "779G", "name": "\u570b\u7968-\u65b0\u838a", "phone": "02-29923888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.44715000352896, 23.473830006808814 ] }, "properties": { "id": "779H", "name": "\u570b\u7968-\u5609\u7fa9", "phone": "05-2162888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30451615004793, 22.664408296772773 ] }, "properties": { "id": "779J", "name": "\u570b\u7968-\u5317\u9ad8\u96c4", "phone": "07-5581777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.69420807281233, 24.165378624684532 ] }, "properties": { "id": "779P", "name": "\u570b\u7968-\u4e5d\u9f0e", "phone": "04-22321688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.31901500775577, 22.667866491194346 ] }, "properties": { "id": "779V", "name": "\u570b\u7968-\u5929\u7965", "phone": "07-3477111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.5295591603239, 24.079245170723514 ] }, "properties": { "id": "779W", "name": "\u570b\u7968-\u5f70\u5316", "phone": "04-7638888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51115952704313, 24.98885944747955 ] }, "properties": { "id": "779X", "name": "\u570b\u7968-\u4e2d\u548c", "phone": "02-29467777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55601739287718, 25.032908691391555 ] }, "properties": { "id": "779Z", "name": "\u570b\u7968-\u5b89\u548c", "phone": "02-27557999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56374706530237, 25.051212713926915 ] }, "properties": { "id": "779b", "name": "\u570b\u7968-\u570b\u969b\u8b49\u5238", "phone": "(02)25288988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54809096127657, 25.05156170475426 ] }, "properties": { "id": "779c", "name": "\u570b\u7968-\u6566\u5317\u6cd5\u4eba", "phone": "02-27760606" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29533190030398, 23.079672207725025 ] }, "properties": { "id": "779e", "name": "\u570b\u7968-\u5357\u79d1", "phone": "06-5890128" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.3212836910708, 22.621230931524472 ] }, "properties": { "id": "779j", "name": "\u570b\u7968-\u548c\u5e73", "phone": "07-7711111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.6698285, 24.1464193 ] }, "properties": { "id": "779m", "name": "\u570b\u7968-\u4e2d\u6e2f", "phone": "04-22069988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56374706530237, 25.051212713926915 ] }, "properties": { "id": "779n", "name": "\u570b\u7968-\u5357\u4eac", "phone": "(02)25287799" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.31168124632619, 24.99349593747367 ] }, "properties": { "id": "779r", "name": "\u570b\u7968-\u6843\u5712", "phone": "(03)338-1123" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55575878823444, 25.037405545009545 ] }, "properties": { "id": "779u", "name": "\u570b\u7968-\u9577\u57ce", "phone": "(02)27008999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.6463508053759, 24.15674542801355 ] }, "properties": { "id": "779v", "name": "\u570b\u7968-\u53f0\u4e2d", "phone": "(04)22553232" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51122610434808, 25.04588424998058 ] }, "properties": { "id": "779z", "name": "\u570b\u7968-\u535a\u611b", "phone": "(02)23899988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53727417627874, 25.054129099486964 ] }, "properties": { "id": "8151", "name": "\u53f0\u65b0-\u5efa\u5317", "phone": "02-25160222" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.42589181238752, 25.023109784138132 ] }, "properties": { "id": "8152", "name": "\u53f0\u65b0-\u65b0\u838a", "phone": "02-22062828" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.3334668505157, 22.642766604849278 ] }, "properties": { "id": "8156", "name": "\u53f0\u65b0-\u4e09\u6c11", "phone": "07-3871166" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29300404380312, 22.710641184151132 ] }, "properties": { "id": "8157", "name": "\u53f0\u65b0-\u5de6\u6960", "phone": "07-3643767" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5328136126953, 25.052326057870577 ] }, "properties": { "id": "8158", "name": "\u53f0\u65b0-\u677e\u6c5f", "phone": "02-25371188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20035604296905, 22.998691187040222 ] }, "properties": { "id": "8159", "name": "\u53f0\u65b0-\u53f0\u5357", "phone": "06-2218988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30512137628241, 22.61333762243996 ] }, "properties": { "id": "815A", "name": "\u53f0\u65b0-\u9ad8\u96c4", "phone": "(07)537-5589" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.6527816695229, 24.141155649443352 ] }, "properties": { "id": "815B", "name": "\u53f0\u65b0-\u53f0\u4e2d", "phone": "(04)24755000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.49958841002872, 22.673407563421847 ] }, "properties": { "id": "815H", "name": "\u53f0\u65b0-\u5c4f\u6771", "phone": "08-722-3377" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.22476264020125, 24.95965748402164 ] }, "properties": { "id": "815S", "name": "\u53f0\u65b0-\u4e2d\u58e2", "phone": "03-2805759" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.31830343626855, 23.304950340662888 ] }, "properties": { "id": "815Y", "name": "\u53f0\u65b0-\u65b0\u71df", "phone": "06-6356100" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53630180076671, 25.050356490639945 ] }, "properties": { "id": "815Z", "name": "\u53f0\u65b0-\u570b\u969b\u8b49\u5238", "phone": "02-23268898" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.39823486215305, 22.60329657368387 ] }, "properties": { "id": "8381", "name": "\u5b89\u6cf0-\u5927\u767c", "phone": "07-7819121" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.3331682728043, 22.729660802703506 ] }, "properties": { "id": "8382", "name": "\u5b89\u6cf0-\u6960\u6893", "phone": "07-3528866" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.50985054871649, 25.053203175831698 ] }, "properties": { "id": "8451", "name": "\u5eb7\u548c-\u5ef6\u5e73", "phone": "02-25567222" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.67763184668469, 24.153715522989273 ] }, "properties": { "id": "8455", "name": "\u5eb7\u548c-\u53f0\u4e2d", "phone": "04-22015988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.96118137251084, 24.80067681515442 ] }, "properties": { "id": "8456", "name": "\u5eb7\u548c-\u65b0\u7af9", "phone": "03-5255678" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20172452674561, 22.994714358842963 ] }, "properties": { "id": "8458", "name": "\u5eb7\u548c-\u53f0\u5357", "phone": "06-2203371" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.44364999928419, 23.46819000509086 ] }, "properties": { "id": "8459", "name": "\u5eb7\u548c-\u5609\u7fa9", "phone": "05-2851100" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.59055927548259, 25.08093323062439 ] }, "properties": { "id": "845A", "name": "\u5eb7\u548c-\u5167\u6e56", "phone": "02-27925858" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51775337262589, 24.999348534301767 ] }, "properties": { "id": "845B", "name": "\u5eb7\u548c-\u6c38\u548c", "phone": "2-86685858" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.47906797537641, 25.019361137984383 ] }, "properties": { "id": "845D", "name": "\u5eb7\u548c-\u677f\u6a4b", "phone": "02-89611788" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 119.57224468809655, 23.570999376811006 ] }, "properties": { "id": "845E", "name": "\u5eb7\u548c-\u6f8e\u6e56", "phone": "06-9268858" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.547935691578, 25.03832728406291 ] }, "properties": { "id": "845F", "name": "\u5eb7\u548c-\u4ec1\u611b", "phone": "02-27511212" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30843266758355, 22.630586336239986 ] }, "properties": { "id": "845J", "name": "\u5eb7\u548c-\u9ad8\u96c4", "phone": "07-2276688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51750208514189, 25.115098877624362 ] }, "properties": { "id": "845R", "name": "\u5eb7\u548c-\u77f3\u724c", "phone": "02-28253188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.29621217988168, 25.045382733307193 ] }, "properties": { "id": "845S", "name": "\u5eb7\u548c-\u5357\u5d01", "phone": "03-3119388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54429156630945, 25.053552449705762 ] }, "properties": { "id": "845U", "name": "\u5eb7\u548c-\u53f0\u5317", "phone": "02-27190123" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.48946906338843, 22.67502402819757 ] }, "properties": { "id": "845X", "name": "\u5eb7\u548c-\u5c4f\u6771", "phone": "08-7349999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56521045118325, 25.04281373711842 ] }, "properties": { "id": "845Y", "name": "\u5eb7\u548c-\u570b\u969b\u8b49\u5238", "phone": "02-87871888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.6700407397215, 24.149165343764878 ] }, "properties": { "id": "8561", "name": "\u65b0\u5149-\u53f0\u4e2d", "phone": "04-23029828" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29639556530071, 22.629170470281768 ] }, "properties": { "id": "8562", "name": "\u65b0\u5149 - \u9ad8\u96c4", "phone": "07-2692188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.0330283257699, 24.814022497983704 ] }, "properties": { "id": "8563", "name": "\u65b0\u5149 - \u65b0\u7af9", "phone": "03-6673228" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.22483253106199, 22.98433687315406 ] }, "properties": { "id": "8564", "name": "\u65b0\u5149-\u53f0\u5357", "phone": "06-2901288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.3136986028678, 24.992343207436345 ] }, "properties": { "id": "8565", "name": "\u65b0\u5149-\u6843\u5712", "phone": "03-3315888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.31379598411905, 22.62909936662012 ] }, "properties": { "id": "8581", "name": "\u806f\u90a6-\u9ad8\u96c4", "phone": "07-2262118" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.34791060294711, 23.556288310365893 ] }, "properties": { "id": "8582", "name": "\u806f\u90a6-\u5609\u7fa9", "phone": "05-2232121" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54925588062044, 25.041821543973978 ] }, "properties": { "id": "8583", "name": "\u806f\u90a6-\u6566\u5316", "phone": "02-27710999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51600312554646, 24.997620416712508 ] }, "properties": { "id": "8584", "name": "\u806f\u90a6-\u96d9\u548c", "phone": "02-29483668" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49526938522649, 25.061403247772095 ] }, "properties": { "id": "8585", "name": "\u806f\u90a6-\u4e09\u91cd", "phone": "02-29792299" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.31210486232645, 25.013699643953977 ] }, "properties": { "id": "8586", "name": "\u806f\u90a6-\u5927\u696d", "phone": "03-3579739" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.65682449268643, 24.116007476860556 ] }, "properties": { "id": "8587", "name": "\u806f\u90a6-\u8208\u4e2d", "phone": "04-22613636" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.23017580379823, 22.9808099029803 ] }, "properties": { "id": "8588", "name": "\u806f\u90a6-\u5bcc\u5f37", "phone": "06-2603298" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51187427849247, 25.113796117446935 ] }, "properties": { "id": "8711", "name": "\u967d\u4fe1-\u77f3\u724c", "phone": "02-28288585" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.50647414370454, 25.007144114738406 ] }, "properties": { "id": "8841", "name": "\u7389\u5c71-\u96d9\u548c", "phone": "02-8923-1313" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.46041494770526, 25.05109393264766 ] }, "properties": { "id": "8842", "name": "\u7389\u5c71-\u65b0\u838a", "phone": "02-29981313" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.33990486530975, 22.637293324297865 ] }, "properties": { "id": "8843", "name": "\u7389\u5c71-\u9ad8\u96c4", "phone": "07-397-1313" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53287034317658, 25.055377277174138 ] }, "properties": { "id": "8844", "name": "\u7389\u5c71-\u677e\u6c5f", "phone": "02-25621313" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.46117204171206, 25.009741326261064 ] }, "properties": { "id": "8846", "name": "\u7389\u5c71-\u677f\u6a4b", "phone": "02-22651313" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.22410425169991, 22.98051318281805 ] }, "properties": { "id": "8847", "name": "\u7389\u5c71-\u53f0\u5357", "phone": "06-2699913" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.44288000328582, 23.479410003370706 ] }, "properties": { "id": "8848", "name": "\u7389\u5c71-\u5609\u7fa9", "phone": "05-2169913" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5339783008776, 25.014787480013904 ] }, "properties": { "id": "8849", "name": "\u7389\u5c71-\u53f0\u5927", "phone": "02-83691313" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52414483875982, 25.095080321000506 ] }, "properties": { "id": "884A", "name": "\u7389\u5c71-\u58eb\u6797", "phone": "02-2833-1313" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.64022826469193, 24.15880914795396 ] }, "properties": { "id": "884B", "name": "\u7389\u5c71-\u53f0\u4e2d", "phone": "04-22589913" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56021223578887, 25.051701775095157 ] }, "properties": { "id": "884C", "name": "\u7389\u5c71-\u5357\u4eac\u6771\u8def", "phone": "02-27651313" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30359946748834, 22.66776453572205 ] }, "properties": { "id": "884D", "name": "\u7389\u5c71-\u5de6\u71df", "phone": "07-5586613" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.50966514159533, 25.04423232549387 ] }, "properties": { "id": "884E", "name": "\u7389\u5c71-\u57ce\u4e2d", "phone": "02-23821313" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.30493985125243, 25.004861189019373 ] }, "properties": { "id": "884F", "name": "\u7389\u5c71-\u6843\u5712", "phone": "03-3366813" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.01198017517058, 24.785481576809666 ] }, "properties": { "id": "884H", "name": "\u7389\u5c71-\u65b0\u7af9", "phone": "03-6669913" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.67976586816964, 24.108785190747636 ] }, "properties": { "id": "884J", "name": "\u7389\u5c71-\u5927\u91cc", "phone": "(04)24079813" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5476906789493, 25.057382833887658 ] }, "properties": { "id": "884L", "name": "\u7389\u5c71-\u570b\u969b\u8b49\u5238", "phone": "(02)55561313" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30843266758355, 22.630586336239986 ] }, "properties": { "id": "8881", "name": "\u570b\u6cf0-\u9ad8\u96c4", "phone": "07-2285888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.67367234076991, 24.142639652918223 ] }, "properties": { "id": "8882", "name": "\u570b\u6cf0-\u53f0\u4e2d", "phone": "04-22107058" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53282589064361, 25.05310745618208 ] }, "properties": { "id": "8883", "name": "\u570b\u6cf0-\u677e\u6c5f", "phone": "02-2181-2888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20328575487899, 22.99343081913905 ] }, "properties": { "id": "8884", "name": "\u570b\u6cf0-\u53f0\u5357", "phone": "(06)2259666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.29754044531819, 25.01759468831495 ] }, "properties": { "id": "8885", "name": "\u570b\u6cf0-\u6843\u5712", "phone": "(03)3567866" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.44596359884193, 25.03462657669604 ] }, "properties": { "id": "8886", "name": "\u570b\u6cf0-\u65b0\u838a", "phone": "(02)22015666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55251260375485, 25.041662456144024 ] }, "properties": { "id": "8887", "name": "\u570b\u6cf0-\u5fe0\u5b5d", "phone": "(02)77117888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54912153699081, 25.02206502637147 ] }, "properties": { "id": "8888", "name": "\u570b\u6cf0-\u6566\u5357", "phone": "02-77111128" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51513031110815, 25.04429820544992 ] }, "properties": { "id": "888A", "name": "\u570b\u6cf0-\u9928\u524d", "phone": "02-23310025" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.47906908932586, 25.018974169601893 ] }, "properties": { "id": "888K", "name": "\u570b\u6cf0-\u677f\u6a4b", "phone": "02-89643888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54912153699081, 25.02206502637147 ] }, "properties": { "id": "888Q", "name": "\u570b\u6cf0-\u570b\u969b\u8b49\u5238", "phone": "02-77123892" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54918468731599, 25.028912522276457 ] }, "properties": { "id": "9101", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u6566\u5357", "phone": "02-27052888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55570799487015, 25.05139504835985 ] }, "properties": { "id": "9103", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u677e\u5c71", "phone": "02-25708889" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30173975791494, 22.620253155022866 ] }, "properties": { "id": "9105", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u9ad8\u76db", "phone": "07-2615211" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.45795929347729, 25.008461659152243 ] }, "properties": { "id": "9108", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u6d77\u5c71", "phone": "02-29699977" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55484748549783, 25.041185677483153 ] }, "properties": { "id": "910D", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5927\u8208", "phone": "(02)55585558" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.67932882032501, 24.138023049092705 ] }, "properties": { "id": "9131", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u6c11\u6b0a", "phone": "04-22208822" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.22238241363277, 23.008386902448816 ] }, "properties": { "id": "9134", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u958b\u5143", "phone": "06-2348899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.96533836853713, 24.812713341478428 ] }, "properties": { "id": "9135", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u7d93\u570b", "phone": "03-5317777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56400659345948, 25.05160846583206 ] }, "properties": { "id": "9136", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u897f\u677e", "phone": "02-27683388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52895885552017, 25.096158025853192 ] }, "properties": { "id": "9137", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u58eb\u6797", "phone": "02-28380567" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.53376077696647, 24.263548678680195 ] }, "properties": { "id": "9138", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u4e2d\u6e2f", "phone": "04-26577599" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.70140133690903, 24.214282897734915 ] }, "properties": { "id": "913D", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u6f6d\u5b50", "phone": "04-25362345" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.74243480777429, 25.129790883787546 ] }, "properties": { "id": "913E", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u57fa\u9686", "phone": "02-24221212" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.4870958647903, 22.671327162033048 ] }, "properties": { "id": "913H", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5c4f\u6771", "phone": "08-7339602" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.50461495615633, 25.037989159205914 ] }, "properties": { "id": "913I", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u842c\u83ef", "phone": "02-23751399" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.44512602061451, 24.985452902052526 ] }, "properties": { "id": "913N", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u571f\u57ce", "phone": "02-22625988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30114598743572, 22.66330999903929 ] }, "properties": { "id": "913R", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5317\u9ad8\u96c4", "phone": "07-5559933" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68581094816516, 24.17989033730249 ] }, "properties": { "id": "913U", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5d07\u5fb7", "phone": "04-22468899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51333641256265, 25.04394390467596 ] }, "properties": { "id": "913Y", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u9928\u524d", "phone": "02-23615678" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49838950480493, 25.05952340742243 ] }, "properties": { "id": "913g", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5357\u4e09\u91cd", "phone": "02-29734388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29087478588022, 22.62303225925372 ] }, "properties": { "id": "9183", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u9ad8\u96c4", "phone": "07-2150077" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.65848090435871, 24.155729463871182 ] }, "properties": { "id": "9184", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u53f0\u4e2d", "phone": "04-23200088" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.19706823204639, 22.995322303021872 ] }, "properties": { "id": "9185", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u53f0\u5357", "phone": "06-2252588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.96284029055191, 24.80630694155966 ] }, "properties": { "id": "9186", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u65b0\u7af9", "phone": "03-5237777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54226127991265, 24.08201552308815 ] }, "properties": { "id": "9187", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5f70\u5316", "phone": "04-7250888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.33238238444845, 22.642339509782317 ] }, "properties": { "id": "9188", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u4e09\u6c11", "phone": "07-3952588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.31114203803266, 24.99250801518787 ] }, "properties": { "id": "9189", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u6843\u5712", "phone": "03-3377555" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.22643450392913, 24.95534687550108 ] }, "properties": { "id": "918A", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u4e2d\u58e2", "phone": "03-4278699" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.47906908932586, 25.018974169601893 ] }, "properties": { "id": "918B", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u677f\u6a4b", "phone": "02-89518089" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52086624247728, 25.02714265053292 ] }, "properties": { "id": "918C", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u53e4\u4ead", "phone": "02-23279288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.21139442401402, 22.991828445949253 ] }, "properties": { "id": "918D", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u6771\u9580", "phone": "06-2290077" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53083737292548, 25.052253307601454 ] }, "properties": { "id": "918E", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5357\u4eac", "phone": "02-25427088" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54292665851061, 24.978014039935744 ] }, "properties": { "id": "918F", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u65b0\u5e97", "phone": "02-29121818" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.45346034550509, 25.05118729858678 ] }, "properties": { "id": "918G", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u65b0\u838a", "phone": "02-89918899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52539377065762, 25.057733615992298 ] }, "properties": { "id": "918H", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u4e2d\u5c71", "phone": "02-21002798" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51462835278072, 25.007332834931628 ] }, "properties": { "id": "918J", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u6c38\u548c", "phone": "02-29207777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.60627270762394, 25.073700774923033 ] }, "properties": { "id": "918K", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u6771\u6e56", "phone": "02-26333988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68792600497504, 24.13048261051955 ] }, "properties": { "id": "918L", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5efa\u6210", "phone": "04-22830099" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.45865999999421, 23.474410000702267 ] }, "properties": { "id": "918M", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5609\u7fa9", "phone": "05-2258666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53086014449656, 25.119017132513306 ] }, "properties": { "id": "918P", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5929\u6bcd", "phone": "02-28767388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54762440067454, 25.04175758057881 ] }, "properties": { "id": "918W", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5fe0\u5b5d", "phone": "02-27771077" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5135552937565, 25.050861139530095 ] }, "properties": { "id": "918X", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u53f0\u5317", "phone": "02-25561133" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.3345159189105, 22.60321523692496 ] }, "properties": { "id": "918c", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u9cf3\u5c71", "phone": "07-7101288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.59217586189092, 25.08218761760509 ] }, "properties": { "id": "918d", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5167\u6e56", "phone": "02-27911999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5504209158739, 25.041704571400746 ] }, "properties": { "id": "918e", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5927\u5b89", "phone": "02-27730899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.61756295053709, 24.34772378887844 ] }, "properties": { "id": "918g", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5927\u7532", "phone": "04-26882828" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.87830068445514, 24.686643046840953 ] }, "properties": { "id": "918i", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u7af9\u5357", "phone": "037-478345" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.41838909078061, 25.0264233743533 ] }, "properties": { "id": "918s", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u4e39\u9cf3", "phone": "02-29082388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.32982390096258, 22.62241277589005 ] }, "properties": { "id": "918u", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u745e\u8c50", "phone": "07-7211828" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51151687433625, 25.05651682923206 ] }, "properties": { "id": "918x", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5ef6\u5e73", "phone": "02-25553888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.75145085836712, 24.75485245293902 ] }, "properties": { "id": "918z", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u5b9c\u862d", "phone": "03-9331999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5476906789493, 25.057382833887658 ] }, "properties": { "id": "9199", "name": "\u7fa4\u76ca\u91d1\u9f0e-\u570b\u969b\u8b49\u5238", "phone": "02-87898888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.67421135814217, 24.14780093700684 ] }, "properties": { "id": "9202", "name": "\u51f1\u57fa-\u4e2d\u6e2f", "phone": "04-22019588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68123910589931, 24.13836560381557 ] }, "properties": { "id": "9204", "name": "\u51f1\u57fa-\u53f0\u4e2d", "phone": "04-22278011" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49624769303578, 25.067376339772945 ] }, "properties": { "id": "9205", "name": "\u51f1\u57fa-\u4e09\u91cd", "phone": "02-29838833" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.31838594628341, 22.63046637194651 ] }, "properties": { "id": "9206", "name": "\u51f1\u57fa-\u9ad8\u96c4", "phone": "(07)222-3211" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51715159807746, 25.00683343055687 ] }, "properties": { "id": "9207", "name": "\u51f1\u57fa-\u6c38\u548c", "phone": "(02)22324567" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.31114203803266, 24.99250801518787 ] }, "properties": { "id": "9208", "name": "\u51f1\u57fa-\u6843\u5712", "phone": "(03)3336622" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29300793184731, 22.79940554768954 ] }, "properties": { "id": "9209", "name": "\u51f1\u57fa-\u5ca1\u5c71", "phone": "076233600" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.45986625111436, 25.005087954512447 ] }, "properties": { "id": "920A", "name": "\u51f1\u57fa-\u677f\u6a4b", "phone": "02-89516688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.50677295613193, 24.999511050886337 ] }, "properties": { "id": "920C", "name": "\u51f1\u57fa-\u96d9\u548c", "phone": "02-22468666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56401916764547, 25.041454803163717 ] }, "properties": { "id": "920D", "name": "\u51f1\u57fa-\u5e02\u5e9c", "phone": "02-27456888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.22166162773554, 22.98565598999399 ] }, "properties": { "id": "920E", "name": "\u51f1\u57fa-\u6771\u9580", "phone": "06-2698899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51695783204148, 25.045724850397423 ] }, "properties": { "id": "920F", "name": "\u51f1\u57fa-\u7ad9\u524d", "phone": "02-23831111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54361856922516, 24.074908198176885 ] }, "properties": { "id": "920G", "name": "\u51f1\u57fa-\u5f70\u5316", "phone": "04-7266565" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.7487464219939, 25.12815623802721 ] }, "properties": { "id": "920H", "name": "\u51f1\u57fa-\u57fa\u9686", "phone": "24202111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.75582133144142, 24.755308150607682 ] }, "properties": { "id": "920M", "name": "\u51f1\u57fa-\u5b9c\u862d", "phone": "03-9334999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.04163339282267, 24.902057500540263 ] }, "properties": { "id": "920N", "name": "\u51f1\u57fa-\u6e56\u53e3", "phone": "03-5907766" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54184832090682, 24.981319146704816 ] }, "properties": { "id": "920V", "name": "\u51f1\u57fa-\u65b0\u5e97", "phone": "02-29155855" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68881407266073, 24.104215522839834 ] }, "properties": { "id": "920W", "name": "\u51f1\u57fa-\u5927\u91cc", "phone": "04-24866988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.15147628264307, 22.756444644829838 ] }, "properties": { "id": "920Z", "name": "\u51f1\u57fa-\u53f0\u6771", "phone": "089-353345" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.22162554325557, 22.985519366879632 ] }, "properties": { "id": "9211", "name": "\u51f1\u57fa-\u53f0\u5357", "phone": "06-2347622" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.4579476857518, 22.47026079834569 ] }, "properties": { "id": "9212", "name": "\u51f1\u57fa-\u6771\u6e2f", "phone": "(08)833-6565" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.28942092018663, 22.661541829112853 ] }, "properties": { "id": "9215", "name": "\u51f1\u57fa-\u9ad8\u7f8e\u9928", "phone": "(07)5544888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54430607555314, 25.053897972398925 ] }, "properties": { "id": "9216", "name": "\u51f1\u57fa-\u4fe1\u7fa9", "phone": "02-27195528" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.57641948558793, 25.04987162553671 ] }, "properties": { "id": "9217", "name": "\u51f1\u57fa-\u677e\u5c71", "phone": "02-27534567" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55124089667815, 25.080819661221177 ] }, "properties": { "id": "9218", "name": "\u51f1\u57fa-\u5927\u76f4", "phone": "(02)85098288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54383571739243, 25.06261647561631 ] }, "properties": { "id": "921C", "name": "\u51f1\u57fa-\u6c11\u6b0a", "phone": "02-25043388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.37227801178788, 24.935912457393407 ] }, "properties": { "id": "921E", "name": "\u51f1\u57fa-\u4e09\u5cfd", "phone": "02-6729988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53086014449656, 25.119017132513306 ] }, "properties": { "id": "921F", "name": "\u51f1\u57fa-\u5929\u6bcd", "phone": "02-28728787" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.43862897535404, 25.08289905893241 ] }, "properties": { "id": "921G", "name": "\u51f1\u57fa-\u4e94\u80a1", "phone": "02-82950066" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.46815445648248, 24.987780008512573 ] }, "properties": { "id": "921J", "name": "\u51f1\u57fa-\u571f\u57ce", "phone": "02-82626998" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.29886472725848, 24.954266581775 ] }, "properties": { "id": "921M", "name": "\u51f1\u57fa-\u516b\u5fb7", "phone": "03-3779688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.45349313866933, 25.045241029771425 ] }, "properties": { "id": "921S", "name": "\u51f1\u57fa-\u5e78\u798f", "phone": "02-89919999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.82991774701135, 24.25262356104572 ] }, "properties": { "id": "921Y", "name": "\u51f1\u57fa-\u6771\u52e2", "phone": "04-25877111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.72246313453645, 24.25504427945391 ] }, "properties": { "id": "9223", "name": "\u51f1\u57fa-\u8c50\u4e2d", "phone": "04-25274180" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.42394322566575, 25.02398084158691 ] }, "properties": { "id": "9224", "name": "\u51f1\u57fa-\u65b0\u838a", "phone": "02-22019898" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.56528651547069, 22.618333080343522 ] }, "properties": { "id": "9225", "name": "\u51f1\u57fa-\u5167\u57d4", "phone": "08-7690888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.65639529076113, 25.06509823540654 ] }, "properties": { "id": "9226", "name": "\u51f1\u57fa-\u6c50\u6b62", "phone": "02-26485959" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5115208594632, 25.04502739906325 ] }, "properties": { "id": "9227", "name": "\u51f1\u57fa-\u57ce\u4e2d", "phone": "2361-6789" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52258820873917, 25.05682549549902 ] }, "properties": { "id": "9229", "name": "\u51f1\u57fa-\u4e2d\u5c71", "phone": "02-77026678" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.49451811155245, 22.669806841426464 ] }, "properties": { "id": "922C", "name": "\u51f1\u57fa-\u5c4f\u6771", "phone": "08-7657000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54430607555314, 25.053897972398925 ] }, "properties": { "id": "922H", "name": "\u51f1\u57fa-\u5fa9\u8208", "phone": "27180718" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.57092387827193, 23.962075745645905 ] }, "properties": { "id": "9231", "name": "\u51f1\u57fa-\u54e1\u6797", "phone": "04-8399988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52466886797144, 25.051949889019834 ] }, "properties": { "id": "9232", "name": "\u51f1\u57fa-\u5efa\u6210", "phone": "02-25588080" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.36471033913739, 25.057730910059668 ] }, "properties": { "id": "9233", "name": "\u51f1\u57fa-\u9577\u5e9a", "phone": "03-3275000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.0143546019488, 24.833499053457487 ] }, "properties": { "id": "9234", "name": "\u51f1\u57fa-\u7af9\u5317", "phone": "03-5552233" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.19640115060855, 22.987593828932575 ] }, "properties": { "id": "9235", "name": "\u51f1\u57fa-\u6c38\u83ef", "phone": "06-2205570" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.43306492542551, 23.709327484787202 ] }, "properties": { "id": "9236", "name": "\u51f1\u57fa-\u864e\u5c3e", "phone": "(05)633-3581" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54850053728308, 25.05135358589174 ] }, "properties": { "id": "9237", "name": "\u51f1\u57fa-\u6566\u5317", "phone": "02-27401166" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52539270389224, 25.093343474270334 ] }, "properties": { "id": "9238", "name": "\u51f1\u57fa-\u58eb\u6797", "phone": "02-28823355" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.6395557473533, 24.15913060995087 ] }, "properties": { "id": "9239", "name": "\u51f1\u57fa-\u5e02\u653f", "phone": "04-2258-9669" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.44393000102575, 23.473510005249587 ] }, "properties": { "id": "9252", "name": "\u51f1\u57fa-\u5609\u7fa9", "phone": "05-2276879" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.01959457617244, 24.782126903481444 ] }, "properties": { "id": "9254", "name": "\u51f1\u57fa-\u79d1\u5712", "phone": "03-6686599" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52249269011226, 25.026639358203326 ] }, "properties": { "id": "9255", "name": "\u51f1\u57fa-\u548c\u5e73", "phone": "02-23697707" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.29215368747525, 25.04769514029347 ] }, "properties": { "id": "9256", "name": "\u51f1\u57fa-\u5357\u5d01", "phone": "03-3129933" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.37520921793916, 25.077895882421952 ] }, "properties": { "id": "9257", "name": "\u51f1\u57fa-\u6797\u53e3", "phone": "02-26025678" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.77190984300096, 24.679546082233387 ] }, "properties": { "id": "9258", "name": "\u51f1\u57fa-\u7f85\u6771", "phone": "03-9534888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.3460623087001, 22.641400234128035 ] }, "properties": { "id": "9259", "name": "\u51f1\u57fa-\u6f84\u65b0", "phone": "07-7809788" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.99497255055482, 24.87571882396046 ] }, "properties": { "id": "9266", "name": "\u51f1\u57fa-\u65b0\u8c50", "phone": "03-5575566" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53511049086421, 25.052216677516075 ] }, "properties": { "id": "9268", "name": "\u51f1\u57fa-\u53f0\u5317", "phone": "02-25166789" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.96646232876482, 24.809628431295874 ] }, "properties": { "id": "9272", "name": "\u51f1\u57fa-\u7af9\u79d1", "phone": "03-5221177" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.08535441512984, 24.742121104343344 ] }, "properties": { "id": "9273", "name": "\u51f1\u57fa-\u7af9\u6771", "phone": "03-5958588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.36141262842624, 22.6247873775034 ] }, "properties": { "id": "9274", "name": "\u51f1\u57fa-\u9cf3\u5c71", "phone": "07-7198899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30171751189829, 22.613540352894827 ] }, "properties": { "id": "9275", "name": "\u51f1\u57fa-\u4e09\u591a", "phone": "07-3383288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.82191680224673, 24.55970693140327 ] }, "properties": { "id": "9276", "name": "\u51f1\u57fa-\u82d7\u6817", "phone": "037-321300" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.25561249054225, 23.02537878267583 ] }, "properties": { "id": "9278", "name": "\u51f1\u57fa-\u6c38\u5eb7", "phone": "06-2038899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54779762359985, 23.709800459542507 ] }, "properties": { "id": "9281", "name": "\u51f1\u57fa-\u6597\u516d", "phone": "05-5376688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.21137244563775, 22.992287519544178 ] }, "properties": { "id": "9283", "name": "\u51f1\u57fa-\u5317\u9580", "phone": "06-2228777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.22638644203194, 24.96599674088113 ] }, "properties": { "id": "9285", "name": "\u51f1\u57fa-\u4e2d\u58e2", "phone": "03-4336989" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.57074205421829, 25.08092442147297 ] }, "properties": { "id": "9287", "name": "\u51f1\u57fa-\u5167\u6e56", "phone": "02-27938388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.47906908932586, 25.018974169601893 ] }, "properties": { "id": "9288", "name": "\u51f1\u57fa-\u57d4\u5898", "phone": "02-89517777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55632767218863, 25.0001711709779 ] }, "properties": { "id": "9289", "name": "\u51f1\u57fa-\u8208\u9686", "phone": "02-29315000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5509348737846, 25.029537676670095 ] }, "properties": { "id": "9291", "name": "\u51f1\u57fa-\u5927\u5b89", "phone": "02-27080606" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.90702636693223, 24.685386320291055 ] }, "properties": { "id": "9296", "name": "\u51f1\u57fa-\u982d\u4efd", "phone": "037-591888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.69341807795026, 24.171561129488683 ] }, "properties": { "id": "9297", "name": "\u51f1\u57fa-\u6587\u5fc3", "phone": "04-22466168" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51151687433625, 25.05651682923206 ] }, "properties": { "id": "9298", "name": "\u51f1\u57fa-\u5ef6\u5e73", "phone": "02-25558877" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55150597524369, 25.084875603296265 ] }, "properties": { "id": "9299", "name": "\u51f1\u57fa-\u570b\u969b\u8b49\u5238", "phone": "02-21818888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.65121767112213, 24.139714438972977 ] }, "properties": { "id": "9302", "name": "\u83ef\u5357\u6c38\u660c-\u53f0\u4e2d", "phone": "04-24719488" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29616467042601, 22.621764093615855 ] }, "properties": { "id": "9303", "name": "\u83ef\u5357\u6c38\u660c-\u9ad8\u96c4", "phone": "07-2728688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.4526325539753, 25.045094355741274 ] }, "properties": { "id": "9305", "name": "\u83ef\u5357\u6c38\u660c-\u65b0\u838a", "phone": "02-22795688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.1843289549481, 22.993355299317443 ] }, "properties": { "id": "9306", "name": "\u83ef\u5357\u6c38\u660c-\u53f0\u5357", "phone": "06-2959988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54339738480424, 25.03493564332671 ] }, "properties": { "id": "9307", "name": "\u83ef\u5357\u6c38\u660c-\u5927\u5b89", "phone": "02-27549696" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.24737378943627, 23.183823944663263 ] }, "properties": { "id": "9308", "name": "\u83ef\u5357\u6c38\u660c-\u9ebb\u8c46", "phone": "06-5720168" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52407136575192, 25.025210131448937 ] }, "properties": { "id": "9309", "name": "\u83ef\u5357\u6c38\u660c-\u53e4\u4ead", "phone": "02-23699588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.31344849061526, 22.6114802523025 ] }, "properties": { "id": "9312", "name": "\u83ef\u5357\u6c38\u660c-\u6c11\u6b0a", "phone": "07-3333133" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.44971999951457, 23.477880006752166 ] }, "properties": { "id": "9314", "name": "\u83ef\u5357\u6c38\u660c-\u5609\u7fa9", "phone": "05-2226848" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.65560631731654, 24.44243613649514 ] }, "properties": { "id": "9315", "name": "\u83ef\u5357\u6c38\u660c-\u82d1\u88e1", "phone": "037-860678" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.44423059064508, 25.169276934812704 ] }, "properties": { "id": "9316", "name": "\u83ef\u5357\u6c38\u660c-\u6de1\u6c34", "phone": "02-26255566" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.39125174808098, 25.07832270627713 ] }, "properties": { "id": "9317", "name": "\u83ef\u5357\u6c38\u660c-\u6797\u53e3", "phone": "02-26018288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.3504142050245, 24.954461716163394 ] }, "properties": { "id": "9319", "name": "\u83ef\u5357\u6c38\u660c-\u9daf\u6b4c", "phone": "02-26776000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.743069495745, 25.129376850489255 ] }, "properties": { "id": "9322", "name": "\u83ef\u5357\u6c38\u660c-\u516c\u8aa0", "phone": "02-24201201" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.35532366079507, 22.567043895094166 ] }, "properties": { "id": "9323", "name": "\u83ef\u5357\u6c38\u660c-\u5c0f\u6e2f", "phone": "07-8068988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.2871877567478, 22.79339171020356 ] }, "properties": { "id": "9324", "name": "\u83ef\u5357\u6c38\u660c-\u5ca1\u5c71", "phone": "07-6255911" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53180412832376, 25.042399028997796 ] }, "properties": { "id": "9325", "name": "\u83ef\u5357\u6c38\u660c-\u5fe0\u5b5d", "phone": "02-23587488" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5445807397667, 25.051642163653675 ] }, "properties": { "id": "9326", "name": "\u83ef\u5357\u6c38\u660c-\u5357\u4eac", "phone": "02-27755688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54335747551778, 23.710687142453047 ] }, "properties": { "id": "9327", "name": "\u83ef\u5357\u6c38\u660c-\u6597\u516d", "phone": "05-5330777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.53831675942214, 22.549178098443257 ] }, "properties": { "id": "9328", "name": "\u83ef\u5357\u6c38\u660c-\u6f6e\u5dde", "phone": "08-7805888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.24149647874056, 23.463971233041935 ] }, "properties": { "id": "9329", "name": "\u83ef\u5357\u6c38\u660c-\u6734\u5b50", "phone": "05-3707688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.35726199596793, 22.62419445902503 ] }, "properties": { "id": "9331", "name": "\u83ef\u5357\u6c38\u660c-\u9cf3\u5c71", "phone": "07-7477600" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.32792985359536, 22.7321765178947 ] }, "properties": { "id": "9332", "name": "\u83ef\u5357\u6c38\u660c-\u6960\u6893", "phone": "07-3542030" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.76984961349979, 24.6783101295938 ] }, "properties": { "id": "9333", "name": "\u83ef\u5357\u6c38\u660c-\u9577\u8679", "phone": "03-9574101" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55794296660697, 25.02986647315562 ] }, "properties": { "id": "9334", "name": "\u83ef\u5357\u6c38\u660c-\u4e16\u8cbf", "phone": "02-27396266" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.25472077379118, 24.962100731439254 ] }, "properties": { "id": "9337", "name": "\u83ef\u5357\u6c38\u660c-\u5167\u58e2", "phone": "03-4519888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.02711463417063, 24.82150182561268 ] }, "properties": { "id": "9339", "name": "\u83ef\u5357\u6c38\u660c-\u7af9\u5317", "phone": "03-6580066" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.91115278462885, 24.68818434657197 ] }, "properties": { "id": "9343", "name": "\u83ef\u5357\u6c38\u660c-\u982d\u4efd", "phone": "037-667999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54828993022954, 25.041748246738788 ] }, "properties": { "id": "9347", "name": "\u83ef\u5357\u6c38\u660c-\u6566\u5357", "phone": "02-27415858" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.46012221499636, 25.007961367307573 ] }, "properties": { "id": "9349", "name": "\u83ef\u5357\u6c38\u660c-\u5408\u6cf0", "phone": "02-29561688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.30797101016033, 24.99121209819961 ] }, "properties": { "id": "9352", "name": "\u83ef\u5357\u6c38\u660c-\u6843\u5712", "phone": "03-3478168" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.82919635481748, 24.25911771743565 ] }, "properties": { "id": "9358", "name": "\u83ef\u5357\u6c38\u660c-\u6771\u52e2", "phone": "04-25881811" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51310571583359, 25.04485397519645 ] }, "properties": { "id": "9359", "name": "\u83ef\u5357\u6c38\u660c-\u4e2d\u6b63", "phone": "02-23821788" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.81898867489289, 24.555180052316743 ] }, "properties": { "id": "9362", "name": "\u83ef\u5357\u6c38\u660c-\u82d7\u6817", "phone": "037-376118" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54090781817867, 24.079499337664533 ] }, "properties": { "id": "9363", "name": "\u83ef\u5357\u6c38\u660c-\u5f70\u5316", "phone": "04-7223700" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.48186039918417, 25.080609955917446 ] }, "properties": { "id": "9369", "name": "\u83ef\u5357\u6c38\u660c-\u4e09\u91cd", "phone": "02-28576789" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.43867503344592, 23.709705780211927 ] }, "properties": { "id": "9377", "name": "\u83ef\u5357\u6c38\u660c-\u864e\u5c3e", "phone": "(05)6334888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.47913624397326, 23.673207233837164 ] }, "properties": { "id": "9381", "name": "\u83ef\u5357\u6c38\u660c-\u6597\u5357", "phone": "(05)5950121" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.15356800557768, 22.754873259631207 ] }, "properties": { "id": "9386", "name": "\u83ef\u5357\u6c38\u660c-\u6771\u6607", "phone": "089-332339" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55091534806718, 25.05773398758345 ] }, "properties": { "id": "9399", "name": "\u83ef\u5357\u6c38\u660c-\u570b\u969b\u8b49\u5238", "phone": "25456888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5171672188255, 25.11345936832575 ] }, "properties": { "id": "9604", "name": "\u5bcc\u90a6-\u967d\u660e", "phone": "02-28230688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.15328764070755, 22.754589179124842 ] }, "properties": { "id": "9608", "name": "\u5bcc\u90a6-\u53f0\u6771", "phone": "089-341022" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55228341974629, 25.038171253374973 ] }, "properties": { "id": "960S", "name": "\u5bcc\u90a6-\u570b\u969b\u8b49\u5238", "phone": "(02)27716699" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.74743519218794, 25.1292314693545 ] }, "properties": { "id": "9614", "name": "\u5bcc\u90a6-\u57fa\u9686", "phone": "2421-3355" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29751096222931, 22.797955609815162 ] }, "properties": { "id": "9616", "name": "\u5bcc\u90a6-\u5ca1\u5c71", "phone": "07-6236123" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.60706020894725, 23.982280436151456 ] }, "properties": { "id": "9621", "name": "\u5bcc\u90a6-\u82b1\u84ee", "phone": "038-350111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.01187466182161, 24.78559227636741 ] }, "properties": { "id": "9622", "name": "\u5bcc\u90a6-\u5712\u5340", "phone": "03-5786868" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51695783204148, 25.045724850397423 ] }, "properties": { "id": "9623", "name": "\u5bcc\u90a6-\u53f0\u5317", "phone": "02-23113333" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.00593653553874, 24.828910457175585 ] }, "properties": { "id": "9624", "name": "\u5bcc\u90a6-\u7af9\u5317", "phone": "03-5515588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.08783703232633, 24.738998027878154 ] }, "properties": { "id": "9625", "name": "\u5bcc\u90a6-\u7af9\u6771", "phone": "03-5818888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56970120867673, 25.081698951044103 ] }, "properties": { "id": "9627", "name": "\u5bcc\u90a6-\u5167\u6e56", "phone": "02\u250087971188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.77085840895968, 24.684524684130597 ] }, "properties": { "id": "9634", "name": "\u5bcc\u90a6-\u7f85\u6771", "phone": "03-9571166" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.22374, 24.9653199 ] }, "properties": { "id": "9636", "name": "\u5bcc\u90a6-\u4e2d\u58e2", "phone": "03-4256767" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.96789530695052, 24.80629113787544 ] }, "properties": { "id": "9647", "name": "\u5bcc\u90a6-\u65b0\u7af9\u83ef\u4fe1", "phone": "03-5228678" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5471136859812, 25.057518322945384 ] }, "properties": { "id": "9651", "name": "\u5bcc\u90a6-\u6c11\u751f", "phone": "02-27128800" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.50647414370454, 25.007144114738406 ] }, "properties": { "id": "9654", "name": "\u5bcc\u90a6-\u6c38\u548c", "phone": "02-22323266" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.46703530163569, 25.02077680456859 ] }, "properties": { "id": "9655", "name": "\u5bcc\u90a6-\u677f\u6a4b", "phone": "02-22546996" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.8225511312893, 24.560845535680333 ] }, "properties": { "id": "9657", "name": "\u5bcc\u90a6-\u82d7\u6817", "phone": "037-327196" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53653746104725, 25.060057653333633 ] }, "properties": { "id": "9658", "name": "\u5bcc\u90a6-\u5efa\u570b", "phone": "02-25095198" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.31282502127142, 22.63201407500027 ] }, "properties": { "id": "9659", "name": "\u5bcc\u90a6-\u9ad8\u96c4", "phone": "07-2366901" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.66283277551318, 24.165543382211506 ] }, "properties": { "id": "965K", "name": "\u5bcc\u90a6-\u53f0\u4e2d", "phone": "04-23129999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54346695436281, 24.074455197375027 ] }, "properties": { "id": "965U", "name": "\u5bcc\u90a6-\u5f70\u5316", "phone": "04-7259456" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54292665851061, 24.978014039935744 ] }, "properties": { "id": "9661", "name": "\u5bcc\u90a6-\u65b0\u5e97", "phone": "02-29178818" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5484832400792, 25.045581624965074 ] }, "properties": { "id": "9663", "name": "\u5bcc\u90a6-\u6566\u5357", "phone": "02-8771-5888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5325981774281, 25.117915568963458 ] }, "properties": { "id": "9664", "name": "\u5bcc\u90a6-\u5929\u6bcd", "phone": "02-28763677" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.30669017452284, 25.001877530767384 ] }, "properties": { "id": "9665", "name": "\u5bcc\u90a6-\u6843\u5712", "phone": "03-3381668" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.63936561864415, 24.142207690527638 ] }, "properties": { "id": "9666", "name": "\u5bcc\u90a6-\u5357\u5c6f", "phone": "04-23801168" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.19181161260451, 22.996557620359255 ] }, "properties": { "id": "9667", "name": "\u5bcc\u90a6-\u53f0\u5357", "phone": "06-2265000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30358616246889, 22.666614235994814 ] }, "properties": { "id": "966F", "name": "\u5bcc\u90a6-\u5de6\u71df", "phone": "07-5570123" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.5669987421793, 23.96676518349115 ] }, "properties": { "id": "9672", "name": "\u5bcc\u90a6-\u54e1\u6797", "phone": "04-8343100" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53848563561931, 25.037312316075305 ] }, "properties": { "id": "9676", "name": "\u5bcc\u90a6-\u4ec1\u611b", "phone": "02-27542866" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49523082508763, 25.070319467979868 ] }, "properties": { "id": "9677", "name": "\u5bcc\u90a6-\u4e09\u91cd", "phone": "02-89818189" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.50151472257565, 25.133558641884644 ] }, "properties": { "id": "9678", "name": "\u5bcc\u90a6-\u5317\u6295", "phone": "02-28973889" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55575878823444, 25.037405545009545 ] }, "properties": { "id": "9679", "name": "\u5bcc\u90a6-\u5ef6\u5409", "phone": "02-27556696" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.75547794500993, 24.7586683682255 ] }, "properties": { "id": "9686", "name": "\u5bcc\u90a6-\u5b9c\u862d", "phone": "03-9369300" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.44522999910235, 23.482930000628155 ] }, "properties": { "id": "9692", "name": "\u5bcc\u90a6-\u5609\u7fa9", "phone": "05-2236556" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30318431120037, 23.305250401032982 ] }, "properties": { "id": "9693", "name": "\u5bcc\u90a6-\u65b0\u71df", "phone": "06-6571000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.4242126783734, 23.557532342462796 ] }, "properties": { "id": "9695", "name": "\u5bcc\u90a6-\u6c11\u96c4", "phone": "05-2063669" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.43272165827663, 23.709313224167115 ] }, "properties": { "id": "9697", "name": "\u5bcc\u90a6-\u864e\u5c3e", "phone": "05-6336611" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30188897787089, 23.56816788354149 ] }, "properties": { "id": "969C", "name": "\u5bcc\u90a6-\u5317\u6e2f", "phone": "05-7831888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53328909055263, 25.055092302029973 ] }, "properties": { "id": "9801", "name": "\u5143\u5927-\u677e\u6c5f", "phone": "02-25010655" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54078020661113, 23.708316979330515 ] }, "properties": { "id": "980C", "name": "\u5143\u5927- \u6597\u516d", "phone": "05-5353456" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.21856935802292, 23.006974508980832 ] }, "properties": { "id": "980D", "name": "\u5143\u5927-\u958b\u5143", "phone": "06-2353366" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.01984023563872, 24.78215269305697 ] }, "properties": { "id": "980K", "name": "\u5143\u5927-\u7af9\u79d1", "phone": "03-5679988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.29151746817342, 25.047922728331656 ] }, "properties": { "id": "980Q", "name": "\u5143\u5927-\u5357\u5d01", "phone": "03-3527777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51728233625933, 25.032780498944202 ] }, "properties": { "id": "980R", "name": "\u5143\u5927-\u5357\u6d77", "phone": "02-23975399" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51814719399378, 25.070588608152608 ] }, "properties": { "id": "980a", "name": "\u5143\u5927-\u627f\u5fb7", "phone": "02-25975888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.55904817557469, 24.23598551413051 ] }, "properties": { "id": "980d", "name": "\u5143\u5927-\u6c99\u9e7f", "phone": "04-26623311" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.5761698767313, 24.270216690187233 ] }, "properties": { "id": "980e", "name": "\u5143\u5927-\u6e05\u6c34", "phone": "04-26238585" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51309587724606, 25.043075555632672 ] }, "properties": { "id": "980h", "name": "\u5143\u5927-\u53f0\u5317", "phone": "02-23830968" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.43867503344592, 23.709705780211927 ] }, "properties": { "id": "980l", "name": "\u5143\u5927-\u864e\u5c3e", "phone": "05-6313000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.20041292079428, 22.993909552925857 ] }, "properties": { "id": "980u", "name": "\u5143\u5927-\u5e9c\u57ce", "phone": "06-2206678" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.64738688198267, 24.170851148974297 ] }, "properties": { "id": "980w", "name": "\u5143\u5927-\u897f\u5c6f", "phone": "04-27067171" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68073422626173, 24.138388286949812 ] }, "properties": { "id": "9812", "name": "\u5143\u5927-\u53f0\u4e2d", "phone": "04-22218777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55170923613213, 25.048080698004828 ] }, "properties": { "id": "9813", "name": "\u5143\u5927-\u516b\u5fb7", "phone": "02-25786666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.19617832481362, 22.97594924181992 ] }, "properties": { "id": "9814", "name": "\u5143\u5927-\u5927\u76ca", "phone": "06-2611151" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.2616853032625, 23.006815325396683 ] }, "properties": { "id": "9815", "name": "\u5143\u5927-\u5927\u7063", "phone": "06-2717766" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.97493921898943, 24.813020695879455 ] }, "properties": { "id": "9816", "name": "\u5143\u5927-\u65b0\u7af9", "phone": "03-5456000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.34172741822783, 22.636424799737625 ] }, "properties": { "id": "9817", "name": "\u5143\u5927-\u6771\u6cf0", "phone": "07-3903333" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.34944981259387, 24.956118440828327 ] }, "properties": { "id": "981A", "name": "\u5143\u5927-\u9daf\u6b4c", "phone": "02-26776611" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.01032994258716, 24.82647957697853 ] }, "properties": { "id": "981B", "name": "\u5143\u5927-\u7af9\u5317", "phone": "03-5536000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.2598400781243, 22.854513722531337 ] }, "properties": { "id": "981C", "name": "\u5143\u5927-\u8def\u7af9", "phone": "07-6977456" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68550079610927, 23.909895632180078 ] }, "properties": { "id": "981D", "name": "\u5143\u5927-\u5357\u6295", "phone": "049-2232111" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.45349313866933, 25.045241029771425 ] }, "properties": { "id": "981E", "name": "\u5143\u5927-\u767c\u8ca1", "phone": "02-29971166" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.42223652118864, 25.019055977821896 ] }, "properties": { "id": "981F", "name": "\u5143\u5927-\u798f\u71df", "phone": "02-22010011" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54221552012775, 24.074378410532198 ] }, "properties": { "id": "981G", "name": "\u5143\u5927-\u5f70\u5316", "phone": "04-7257001" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52671544733134, 25.1183525689779 ] }, "properties": { "id": "981I", "name": "\u5143\u5927-\u5929\u6bcd", "phone": "02-28722345" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.39797691026882, 22.502257114890952 ] }, "properties": { "id": "981K", "name": "\u5143\u5927-\u6797\u5712", "phone": "07-6433001" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29878816334798, 22.709898982396883 ] }, "properties": { "id": "981L", "name": "\u5143\u5927-\u8392\u5149", "phone": "07-3651356" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.82160840444624, 24.55968452719333 ] }, "properties": { "id": "981M", "name": "\u5143\u5927-\u82d7\u6817", "phone": "037-333611" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 118.31954720449757, 24.43861490798446 ] }, "properties": { "id": "981N", "name": "\u5143\u5927-\u91d1\u9580", "phone": "082-372367" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.72022663198314, 24.13000834444139 ] }, "properties": { "id": "981Q", "name": "\u5143\u5927-\u592a\u5e73", "phone": "04-22768859" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68253093534231, 23.756567728734453 ] }, "properties": { "id": "981R", "name": "\u5143\u5927-\u7af9\u5c71", "phone": "049-2652633" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68569512829312, 24.169859885786213 ] }, "properties": { "id": "981S", "name": "\u5143\u5927-\u5d07\u5fb7", "phone": "04-22333398" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52672651320907, 25.044200325643104 ] }, "properties": { "id": "981U", "name": "\u5143\u5927-\u83ef\u5c71", "phone": "02-23223388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.42594759927167, 23.5557103152629 ] }, "properties": { "id": "981V", "name": "\u5143\u5927-\u6c11\u96c4", "phone": "05-2268899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53246603970071, 25.03527506223581 ] }, "properties": { "id": "981X", "name": "\u5143\u5927-\u6771\u9580", "phone": "02-23959988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54045130724482, 22.55665730304923 ] }, "properties": { "id": "981Z", "name": "\u5143\u5927-\u6f6e\u5dde", "phone": "08-7891678" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29316036901521, 22.966708503857625 ] }, "properties": { "id": "981a", "name": "\u5143\u5927-\u6b78\u4ec1", "phone": "06-3305888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.17789962640872, 23.162333499195682 ] }, "properties": { "id": "981e", "name": "\u5143\u5927-\u4f73\u91cc", "phone": "06-7232888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68053540777612, 24.105973976002446 ] }, "properties": { "id": "981g", "name": "\u5143\u5927-\u5927\u91cc", "phone": "04-24066598" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.49184586796635, 22.670010701890977 ] }, "properties": { "id": "981h", "name": "\u5143\u5927-\u5c4f\u6771\u6c11\u751f", "phone": "08-7323789" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.46036620497165, 23.80131565094799 ] }, "properties": { "id": "981i", "name": "\u5143\u5927-\u897f\u87ba", "phone": "05-5870123" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52539270389224, 25.093343474270334 ] }, "properties": { "id": "981j", "name": "\u5143\u5927-\u58eb\u6797", "phone": "02-28830202" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29659603155658, 22.629351962991414 ] }, "properties": { "id": "981m", "name": "\u5143\u5927-\u524d\u91d1", "phone": "07-2152888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.482195222677, 22.88793592303292 ] }, "properties": { "id": "981n", "name": "\u5143\u5927-\u65d7\u5c71", "phone": "07-6625578" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56157189367383, 25.051259367732236 ] }, "properties": { "id": "981p", "name": "\u5143\u5927-\u677e\u5c71", "phone": "02-27535888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49920788792575, 25.035922640895617 ] }, "properties": { "id": "981q", "name": "\u5143\u5927-\u824b\u823a", "phone": "02-23363588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.49094267229353, 22.677037090104193 ] }, "properties": { "id": "981r", "name": "\u5143\u5927-\u5c4f\u5357", "phone": "08-7361777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29887849966534, 23.129475249349383 ] }, "properties": { "id": "981y", "name": "\u5143\u5927-\u5584\u5316", "phone": "06-5830888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.96387647046174, 24.798954377184888 ] }, "properties": { "id": "981z", "name": "\u5143\u5927-\u5927\u7d71", "phone": "03-5226166" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.45831886910439, 24.988361553569128 ] }, "properties": { "id": "9822", "name": "\u5143\u5927-\u571f\u57ce\u5b78\u5e9c", "phone": "02-22635000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.66140911771622, 24.146893908777802 ] }, "properties": { "id": "9824", "name": "\u5143\u5927-\u5411\u4e0a", "phone": "04-23028588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.3180300589156, 23.304821016905027 ] }, "properties": { "id": "9825", "name": "\u5143\u5927-\u65b0\u71df", "phone": "06-6351600" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.23580955026651, 22.998791977501494 ] }, "properties": { "id": "9829", "name": "\u5143\u5927-\u6c38\u5eb7", "phone": "06-2215888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.77199598801013, 24.6790942277795 ] }, "properties": { "id": "982A", "name": "\u5143\u5927-\u7f85\u6771", "phone": "03-9532888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30555236173936, 22.660963029466313 ] }, "properties": { "id": "982B", "name": "\u5143\u5927-\u535a\u611b", "phone": "07-5571133" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.3130182404354, 22.632484507814564 ] }, "properties": { "id": "982C", "name": "\u5143\u5927-\u516d\u5408", "phone": "07-2364788" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55627991115894, 25.04115534988096 ] }, "properties": { "id": "982F", "name": "\u5143\u5927-\u5fe0\u5b5d\u9f0e\u5bcc", "phone": "02-87739666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30241070317618, 22.616445003020388 ] }, "properties": { "id": "9831", "name": "\u5143\u5927-\u56db\u7dad", "phone": "07-3306666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54914579883872, 25.030623215987312 ] }, "properties": { "id": "9833", "name": "\u5143\u5927-\u6566\u5316", "phone": "02-27541566" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.22404077448398, 24.95730866271839 ] }, "properties": { "id": "9834", "name": "\u5143\u5927-\u4e2d\u58e2", "phone": "03-4227188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.57104956371577, 23.95544838587079 ] }, "properties": { "id": "9835", "name": "\u5143\u5927-\u54e1\u6797\u4e2d\u5c71", "phone": "04-8358131" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30188897787089, 23.56816788354149 ] }, "properties": { "id": "9837", "name": "\u5143\u5927-\u5317\u6e2f", "phone": "05-7838222" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.7088491559113, 24.250925724265016 ] }, "properties": { "id": "9838", "name": "\u5143\u5927-\u8c50\u539f", "phone": "04-25252511" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.22340647150024, 22.987364751444712 ] }, "properties": { "id": "983B", "name": "\u5143\u5927-\u6797\u68ee", "phone": "06-2745088" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.45965701041843, 25.045190325865892 ] }, "properties": { "id": "983G", "name": "\u5143\u5927-\u4e0a\u65b0\u838a", "phone": "02-89911188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.18255473442218, 23.22913238402248 ] }, "properties": { "id": "983K", "name": "\u5143\u5927-\u5b78\u7532", "phone": "06-7838989" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56731982932799, 24.98833379889497 ] }, "properties": { "id": "983M", "name": "\u5143\u5927-\u6728\u67f5", "phone": "02-86619168" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54605272814307, 25.02487473960709 ] }, "properties": { "id": "983N", "name": "\u5143\u5927-\u5927\u5b89", "phone": "02-27541866" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.90686951336676, 24.685105555205865 ] }, "properties": { "id": "983U", "name": "\u5143\u5927-\u982d\u4efd", "phone": "037-683168" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.87885694367807, 24.68660772477575 ] }, "properties": { "id": "983V", "name": "\u5143\u5927-\u7af9\u5357", "phone": "03-7477890" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.69035325170306, 24.113157987870032 ] }, "properties": { "id": "983W", "name": "\u5143\u5927-\u5927\u91cc\u5fb7\u82b3", "phone": "04-24833000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.33112188548711, 22.595700098097105 ] }, "properties": { "id": "983Z", "name": "\u5143\u5927-\u9cf3\u5c71", "phone": "07-8133066" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.08932764012906, 24.730103429690054 ] }, "properties": { "id": "983f", "name": "\u5143\u5927-\u7af9\u6771", "phone": "03-5952166" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.64758896059143, 24.225156142546776 ] }, "properties": { "id": "983i", "name": "\u5143\u5927-\u5927\u96c5", "phone": "04-25608888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54389216881472, 25.037398245226957 ] }, "properties": { "id": "983j", "name": "\u5143\u5927-\u4ec1\u611b", "phone": "02-27067777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53951732309214, 24.972990270244917 ] }, "properties": { "id": "984C", "name": "\u5143\u5927-\u65b0\u5e97\u4e2d\u6b63", "phone": "02-29155588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51205867082078, 24.99098061940405 ] }, "properties": { "id": "984E", "name": "\u5143\u5927-\u5357\u52e2\u89d2", "phone": "02-86689955" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54142394764395, 24.99360455456848 ] }, "properties": { "id": "984H", "name": "\u5143\u5927-\u666f\u7f8e", "phone": "02-86638886" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5143904411381, 25.04591436900629 ] }, "properties": { "id": "984K", "name": "\u5143\u5927-\u9928\u524d", "phone": "02-23113030" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.57512766177736, 25.040712438154998 ] }, "properties": { "id": "9852", "name": "\u5143\u5927-\u5927\u677e\u5c71", "phone": "02-87805277" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.65070971062595, 24.146867577739748 ] }, "properties": { "id": "9853", "name": "\u5143\u5927-\u5357\u5c6f", "phone": "04-23269999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.6943371433014, 24.1707811821158 ] }, "properties": { "id": "9854", "name": "\u5143\u5927-\u6587\u5fc3\u8208\u5b89", "phone": "04-22339983" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.60138394292562, 23.98972249563759 ] }, "properties": { "id": "9856", "name": "\u5143\u5927-\u82b1\u84ee", "phone": "03-8357588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.48007059152195, 25.08065766454484 ] }, "properties": { "id": "9857", "name": "\u5143\u5927-\u6771\u8606", "phone": "02-22886699" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.21177767740993, 24.863535531239435 ] }, "properties": { "id": "9858", "name": "\u5143\u5927-\u9f8d\u6f6d", "phone": "03-4808699" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.96455002852625, 24.812200331763783 ] }, "properties": { "id": "9859", "name": "\u5143\u5927-\u65b0\u7af9\u7d93\u570b", "phone": "03-5359888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.35236736167732, 22.62681319938396 ] }, "properties": { "id": "985C", "name": "\u5143\u5927-\u9cf3\u4e2d", "phone": "07-7199889" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54310362458759, 25.052067367514937 ] }, "properties": { "id": "9862", "name": "\u5143\u5927-\u5357\u4eac", "phone": "02-27188888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53172803111879, 25.026139630387227 ] }, "properties": { "id": "9863", "name": "\u5143\u5927-\u65b0\u548c\u5e73", "phone": "02-23687733" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.59187437157861, 25.068678818075647 ] }, "properties": { "id": "9867", "name": "\u5143\u5927-\u5317\u6210\u529f", "phone": "02-27928288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.665768211179, 24.173202216300034 ] }, "properties": { "id": "9868", "name": "\u5143\u5927-\u6587\u5fc3", "phone": "04-22932233" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.44650213814303, 25.03835493541679 ] }, "properties": { "id": "9869", "name": "\u5143\u5927-\u65b0\u76db", "phone": "02-29969966" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.74059732807495, 25.130152899897983 ] }, "properties": { "id": "986K", "name": "\u5143\u5927-\u57fa\u9686\u5b5d\u4e8c", "phone": "02-24202626" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55627991115894, 25.04115534988096 ] }, "properties": { "id": "9871", "name": "\u5143\u5927-\u5fe0\u5b5d", "phone": "02-27766288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54383571739243, 25.06261647561631 ] }, "properties": { "id": "9872", "name": "\u5143\u5927-\u5fa9\u5317", "phone": "02-25095998" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.50906087687882, 25.041934678266177 ] }, "properties": { "id": "9873", "name": "\u5143\u5927-\u897f\u9580", "phone": "02-23893388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.50677295613193, 24.999511050886337 ] }, "properties": { "id": "9874", "name": "\u5143\u5927-\u96d9\u548c", "phone": "02-22483388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.44213212468335, 24.976224229963208 ] }, "properties": { "id": "9875", "name": "\u5143\u5927-\u571f\u57ce\u6c38\u5be7", "phone": "02-22709191" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.19386324555818, 22.995001078540803 ] }, "properties": { "id": "9878", "name": "\u5143\u5927-\u91d1\u83ef", "phone": "06-2207999" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.47906965502085, 25.017654458969236 ] }, "properties": { "id": "9879", "name": "\u5143\u5927-\u677f\u6a4b\u4e09\u6c11", "phone": "02-29588887" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.14691032416096, 24.910099363319063 ] }, "properties": { "id": "987A", "name": "\u5143\u5927-\u694a\u6885", "phone": "03-4882688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54670652354615, 23.71110648713886 ] }, "properties": { "id": "9884", "name": "\u5143\u5927-\u93ae\u5317", "phone": "05-5362088" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51456363010979, 25.00995109209561 ] }, "properties": { "id": "9888", "name": "\u5143\u5927-\u946b\u6c38\u548c", "phone": "02-82311333" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.57316644637287, 23.968898328933115 ] }, "properties": { "id": "9889", "name": "\u5143\u5927-\u54e1\u6797", "phone": "04-8341188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.29609209187994, 25.023430299770137 ] }, "properties": { "id": "988B", "name": "\u5143\u5927-\u6843\u5712", "phone": "03-3268777" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49101380313246, 25.05974445614952 ] }, "properties": { "id": "988C", "name": "\u5143\u5927-\u4e09\u91cd", "phone": "02-89857788" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.36532372998435, 25.058892685177323 ] }, "properties": { "id": "988V", "name": "\u5143\u5927-\u9577\u5e9a", "phone": "(03)397-8787" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52112704585363, 25.007700176530903 ] }, "properties": { "id": "9891", "name": "\u5143\u5927-\u6c38\u548c", "phone": "02-29201234" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.4962895092327, 22.68546307453623 ] }, "properties": { "id": "9892", "name": "\u5143\u5927-\u5c4f\u6771", "phone": "08-7385555" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52500393091108, 25.105764576725797 ] }, "properties": { "id": "9893", "name": "\u5143\u5927-\u5927\u5929\u6bcd", "phone": "02-28312888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.31586436350642, 24.991132083212282 ] }, "properties": { "id": "9894", "name": "\u5143\u5927-\u6843\u8208", "phone": "03-3327700" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.21792835003272, 22.98471084307604 ] }, "properties": { "id": "9896", "name": "\u5143\u5927-\u53f0\u5357", "phone": "06-2741866" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.44518717934065, 24.985541502671243 ] }, "properties": { "id": "9897", "name": "\u5143\u5927-\u571f\u57ce", "phone": "02-22708369" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.4465227829294, 25.03964486176146 ] }, "properties": { "id": "9898", "name": "\u5143\u5927-\u65b0\u838a", "phone": "02-29977123" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.44092193410515, 25.169566180300205 ] }, "properties": { "id": "9899", "name": "\u5143\u5927-\u6de1\u6c34", "phone": "02-26251966" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49856954246648, 25.131038726484828 ] }, "properties": { "id": "989A", "name": "\u5143\u5927-\u5317\u6295", "phone": "02-28961212" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.66012382637193, 24.156273525941895 ] }, "properties": { "id": "989B", "name": "\u5143\u5927-\u53f0\u4e2d\u4e2d\u6e2f", "phone": "04-23289000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.46012221499636, 25.007961367307573 ] }, "properties": { "id": "989C", "name": "\u5143\u5927-\u677f\u6a4b", "phone": "02-29638000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.28924485940607, 22.683810845577522 ] }, "properties": { "id": "989D", "name": "\u5143\u5927-\u5de6\u71df", "phone": "07-5878899" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68224263773618, 23.974064312940165 ] }, "properties": { "id": "989E", "name": "\u5143\u5927-\u8349\u5c6f", "phone": "049-2354506" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.31665395364739, 22.647671995386883 ] }, "properties": { "id": "989F", "name": "\u5143\u5927-\u9ad8\u96c4", "phone": "07-3855678" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51872124233834, 25.052873731025965 ] }, "properties": { "id": "989G", "name": "\u5143\u5927-\u5927\u540c", "phone": "02-25598585" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.46986505652634, 25.083415706412673 ] }, "properties": { "id": "989I", "name": "\u5143\u5927-\u8606\u6d32", "phone": "02-22891199" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.54593928525739, 24.0835049428733 ] }, "properties": { "id": "989J", "name": "\u5143\u5927-\u5f70\u5316\u6c11\u751f", "phone": "04-7261988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.31114203803266, 24.99250801518787 ] }, "properties": { "id": "989L", "name": "\u5143\u5927-\u6210\u529f", "phone": "03-3353399" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.59330144601653, 25.083048642448958 ] }, "properties": { "id": "989N", "name": "\u5143\u5927-\u5167\u6e56", "phone": "02-27933636" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5492885497475, 25.04056811116412 ] }, "properties": { "id": "989P", "name": "\u5143\u5927-\u6566\u5357", "phone": "02-27752121" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.65378841138279, 25.062486149734227 ] }, "properties": { "id": "989Q", "name": "\u5143\u5927-\u6c50\u6b62", "phone": "02-26482277" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.43157897893857, 24.05561736206507 ] }, "properties": { "id": "989S", "name": "\u5143\u5927-\u9e7f\u6e2f", "phone": "04-7751211" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.62267036454291, 24.342577900905663 ] }, "properties": { "id": "989U", "name": "\u5143\u5927-\u5927\u7532", "phone": "04-26883399" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.49626518131451, 25.068208688513103 ] }, "properties": { "id": "989V", "name": "\u5143\u5927-\u5317\u4e09\u91cd", "phone": "02-29713311" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.72246313453645, 24.25504427945391 ] }, "properties": { "id": "989W", "name": "\u5143\u5927-\u8c50\u539f\u7ad9\u524d", "phone": "04-25204888" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.56474618054457, 25.05976408947412 ] }, "properties": { "id": "989X", "name": "\u5143\u5927-\u6c11\u751f", "phone": "02-87872118" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.74758091169237, 25.12916517497072 ] }, "properties": { "id": "989Y", "name": "\u5143\u5927-\u57fa\u9686", "phone": "02-24246688" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.35663738406656, 22.5670365332859 ] }, "properties": { "id": "989Z", "name": "\u5143\u5927-\u5c0f\u6e2f", "phone": "07-8020068" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.65285200443665, 24.44029030508318 ] }, "properties": { "id": "989a", "name": "\u5143\u5927-\u82d1\u88e1", "phone": "037869779" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68569512829312, 24.169859885786213 ] }, "properties": { "id": "989d", "name": "\u5143\u5927-\u5317\u5c6f", "phone": "04-22389555" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.50227584108332, 24.999659793012313 ] }, "properties": { "id": "989e", "name": "\u5143\u5927-\u4e2d\u548c", "phone": "02-22452299" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.45775568814264, 22.470232608294967 ] }, "properties": { "id": "989f", "name": "\u5143\u5927-\u6771\u6e2f", "phone": "08-8338558" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.4472900045035, 23.48344000347856 ] }, "properties": { "id": "989g", "name": "\u5143\u5927-\u5609\u7fa9", "phone": "05-2237666" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.4232781473561, 24.991027994542804 ] }, "properties": { "id": "989j", "name": "\u5143\u5927-\u6a39\u6797", "phone": "02-26759585" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52536702327014, 25.023505222209298 ] }, "properties": { "id": "989k", "name": "\u5143\u5927-\u53e4\u4ead", "phone": "02-23698877" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.57234211793559, 25.04110495392839 ] }, "properties": { "id": "989m", "name": "\u5143\u5927-\u4fe1\u7fa9", "phone": "02-87878732" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54367316718195, 25.05204949387523 ] }, "properties": { "id": "989z", "name": "\u5143\u5927-\u570b\u969b\u8b49\u5238", "phone": "02-2718-1234" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.3338516527339, 22.602118135364492 ] }, "properties": { "id": "9A61", "name": "\u6c38\u8c50\u91d1-\u9cf3\u5c71", "phone": "07-726-3000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.48957035317076, 22.675317402185232 ] }, "properties": { "id": "9A69", "name": "\u6c38\u8c50\u91d1-\u5c4f\u6771", "phone": "08-765-5457" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.96555674858239, 23.96643271379503 ] }, "properties": { "id": "9A79", "name": "\u6c38\u8c50\u91d1-\u57d4\u91cc", "phone": "049-298-9988" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51313466224889, 25.046858563293043 ] }, "properties": { "id": "9A88", "name": "\u6c38\u8c50\u91d1-\u570b\u969b\u8b49\u5238", "phone": "23123866" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54850053728308, 25.05135358589174 ] }, "properties": { "id": "9A89", "name": "\u6c38\u8c50\u91d1-\u6566\u5317", "phone": "02-81615000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55001154951691, 25.02710616910999 ] }, "properties": { "id": "9A8F", "name": "\u6c38\u8c50\u91d1-\u6566\u5357", "phone": "02-2377-8355" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.57761139009415, 25.04769134038912 ] }, "properties": { "id": "9A91", "name": "\u6c38\u8c50\u91d1-\u677e\u5c71", "phone": "02-2766-3315" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53327426552308, 25.053814658500837 ] }, "properties": { "id": "9A92", "name": "\u6c38\u8c50\u91d1-\u842c\u76db", "phone": "02-2501-1451" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51159363625914, 25.044357688075525 ] }, "properties": { "id": "9A96", "name": "\u6c38\u8c50\u91d1-\u535a\u611b", "phone": "02-2311-9144" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.9673082706535, 24.808101880081118 ] }, "properties": { "id": "9A97", "name": "\u6c38\u8c50\u91d1-\u65b0\u7af9", "phone": "03-526-8198" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.19704245102339, 25.066318723490017 ] }, "properties": { "id": "9A98", "name": "\u6c38\u8c50\u91d1-\u5927\u5712", "phone": "03-385-3998" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.22470864481569, 24.959591477704972 ] }, "properties": { "id": "9A99", "name": "\u6c38\u8c50\u91d1-\u4e2d\u58e2", "phone": "03-422-4800" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.77195700333975, 24.677884996991274 ] }, "properties": { "id": "9A9A", "name": "\u6c38\u8c50\u91d1-\u7f85\u6771", "phone": "03-956-7181" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51063566026197, 25.00199136294024 ] }, "properties": { "id": "9A9B", "name": "\u6c38\u8c50\u91d1-\u4e2d\u548c", "phone": "02-2231-3453" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.57982188951588, 23.96310714236305 ] }, "properties": { "id": "9A9C", "name": "\u6c38\u8c50\u91d1-\u54e1\u6797", "phone": "04-836-7338" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55546283202098, 25.041168599396077 ] }, "properties": { "id": "9A9D", "name": "\u6c38\u8c50\u91d1-\u5fe0\u5b5d", "phone": "02-2771-6588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.4609072531808, 25.009002802187222 ] }, "properties": { "id": "9A9E", "name": "\u6c38\u8c50\u91d1-\u677f\u6a4b", "phone": "02-2959-3200" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52726207969647, 25.104805500993297 ] }, "properties": { "id": "9A9G", "name": "\u6c38\u8c50\u91d1-\u5929\u6bcd", "phone": "02-8866-1992" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.4521710781931, 25.045812379092894 ] }, "properties": { "id": "9A9H", "name": "\u6c38\u8c50\u91d1-\u65b0\u838a", "phone": "02-8992-2118" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.47103075976142, 25.027958646705972 ] }, "properties": { "id": "9A9J", "name": "\u6c38\u8c50\u91d1-\u677f\u65b0", "phone": "02-2253-3458" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.48594477998098, 25.06494228283764 ] }, "properties": { "id": "9A9K", "name": "\u6c38\u8c50\u91d1-\u4e09\u91cd", "phone": "02-2981-0112" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.70963092562253, 24.250508434758146 ] }, "properties": { "id": "9A9L", "name": "\u6c38\u8c50\u91d1-\u53f0\u4e2d", "phone": "04-2202-2940" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.68775039480101, 23.907078197370453 ] }, "properties": { "id": "9A9M", "name": "\u6c38\u8c50\u91d1-\u5357\u6295", "phone": "049-220-1932" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.29713408245324, 25.017871405255995 ] }, "properties": { "id": "9A9N", "name": "\u6c38\u8c50\u91d1-\u6843\u76db", "phone": "03-357-5585" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.01009841235378, 24.827897641481012 ] }, "properties": { "id": "9A9P", "name": "\u6c38\u8c50\u91d1-\u7af9\u5317", "phone": "03-553-8388" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.71834915989838, 24.250155167830545 ] }, "properties": { "id": "9A9Q", "name": "\u6c38\u8c50\u91d1-\u8c50\u539f", "phone": "04-2528-2188" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55108090979405, 25.03341709476413 ] }, "properties": { "id": "9A9R", "name": "\u6c38\u8c50\u91d1-\u4fe1\u7fa9", "phone": "02-2705-6588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.53826022613552, 25.051780418217778 ] }, "properties": { "id": "9A9S", "name": "\u6c38\u8c50\u91d1-\u5357\u4eac", "phone": "02-2508-2335" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.52377471739418, 25.049447283756848 ] }, "properties": { "id": "9A9U", "name": "\u6c38\u8c50\u91d1-\u4e2d\u6b63", "phone": "02-2531-3135" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.6395557473533, 24.15913060995087 ] }, "properties": { "id": "9A9W", "name": "\u6c38\u8c50\u91d1-\u5e02\u653f", "phone": "04-2254-8935" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.9895408359819, 24.800064829646068 ] }, "properties": { "id": "9A9X", "name": "\u6c38\u8c50\u91d1-\u7af9\u79d1", "phone": "03-575-2000" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.46804673041318, 25.012823356377147 ] }, "properties": { "id": "9A9Y", "name": "\u6c38\u8c50\u91d1-\u677f\u76db", "phone": "02-2958-6918" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.5421963677237, 25.06254940663512 ] }, "properties": { "id": "9A9Z", "name": "\u6c38\u8c50\u91d1-\u5fa9\u8208", "phone": "02-2502-8588" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.30512137628241, 22.61333762243996 ] }, "properties": { "id": "9A9a", "name": "\u6c38\u8c50\u91d1-\u82d3\u96c5", "phone": "07-537-5800" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.43591682554879, 23.707401143107862 ] }, "properties": { "id": "9A9b", "name": "\u6c38\u8c50\u91d1-\u864e\u5c3e", "phone": "05-636-5288" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.23284626403137, 23.009827415477957 ] }, "properties": { "id": "9A9c", "name": "\u6c38\u8c50\u91d1-\u6c38\u5eb7", "phone": "06-302-5982" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.51793123965273, 25.03010774323751 ] }, "properties": { "id": "9A9d", "name": "\u6c38\u8c50\u91d1-\u53e4\u4ead", "phone": "02-2321-8345" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.32808160869101, 22.629694426770463 ] }, "properties": { "id": "9A9e", "name": "\u6c38\u8c50\u91d1-\u9ad8\u96c4", "phone": "07-723-2800" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.6463508053759, 24.15674542801355 ] }, "properties": { "id": "9A9f", "name": "\u6c38\u8c50\u91d1-\u4e2d\u76db", "phone": "04-2258-7220" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.55958901545932, 25.085129327240065 ] }, "properties": { "id": "9A9g", "name": "\u6c38\u8c50\u91d1-\u5167\u6e56", "phone": "02-2657-1998" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.19727671390498, 22.986223429449304 ] }, "properties": { "id": "9A9h", "name": "\u6c38\u8c50\u91d1-\u53f0\u5357", "phone": "06-224-9998" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.54292665851061, 24.978014039935744 ] }, "properties": { "id": "9A9i", "name": "\u6c38\u8c50\u91d1-\u65b0\u5e97", "phone": "02-2911-6395" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.44602999905491, 23.479710004329007 ] }, "properties": { "id": "9A9j", "name": "\u6c38\u8c50\u91d1-\u5609\u7fa9", "phone": "05-229-1345" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.5403739761311, 22.551911995873866 ] }, "properties": { "id": "9A9q", "name": "\u6c38\u8c50\u91d1-\u6f6e\u5dde", "phone": "08-789-0122" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.29690474406264, 22.66047851597464 ] }, "properties": { "id": "9A9r", "name": "\u6c38\u8c50\u91d1-\u5317\u9ad8\u96c4", "phone": "07-555-0455" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 120.5409354863066, 24.078109090527274 ] }, "properties": { "id": "9A9s", "name": "\u6c38\u8c50\u91d1-\u5f70\u5316", "phone": "04-722-4976" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 121.30792079267425, 24.990936296998363 ] }, "properties": { "id": "9A9x", "name": "\u6c38\u8c50\u91d1-\u6843\u5712", "phone": "03-335-2581" } } ] } ================================================ FILE: twnews/res/ticksmap-template.html ================================================ 分點進出買賣對照
買進熱點
賣出熱點
================================================ FILE: twnews/search.py ================================================ """ 新聞搜尋模組 """ import re import time import urllib.parse from string import Template from datetime import datetime from bs4 import BeautifulSoup from bs4.element import Tag import twnews.common from twnews.soup import NewsSoup def visit_dict(dict_node, path): """ 用 CSS Selector 的形式拜訪 dict """ keys = [] if path != '': keys = path.split(' > ') visited = dict_node for key in keys: visited = visited[key] return visited def filter_duplicated(results): """ 以連結為鍵值去重複化 """ filtered = [] logger = twnews.common.get_logger() for (cidx, result) in enumerate(results): duplicated = False pidx = -1 for pidx in range(cidx): previous = results[pidx] if result['link'] == previous['link']: duplicated = True break if not duplicated: filtered.append(result) else: logger.warning('查詢結果的 %d, %d 筆重複,新聞網址 %s', cidx, pidx, result['link']) return filtered class NewsSearchException(Exception): """ 新聞搜尋例外 """ class NewsSearch: """ 新聞搜尋器 """ def __init__(self, channel, limit=25, beg_date=None, end_date=None, proxy_first=False): """ 配置新聞搜尋器 """ # pylint: disable=too-many-arguments # 防止用中時搜尋 if channel == 'chinatimes': msg = '頻道 {} 不支援搜尋功能'.format(channel) raise NewsSearchException(msg) # 防止開始日期和結束日期只設定了一個 if beg_date is None or end_date is None: if end_date is not None: msg = '遺漏了開始日期' raise NewsSearchException(msg) if beg_date is not None: msg = '遺漏了結束日期' raise NewsSearchException(msg) # 防止開始日期和結束日期格式錯誤 self.params = { 'beg_date': None, 'end_date': None, 'channel': channel, 'limit': limit, 'proxy_first': proxy_first } try: if beg_date is not None: self.params['beg_date'] = datetime.strptime(beg_date, '%Y-%m-%d') if end_date is not None: self.params['end_date'] = datetime.strptime(end_date, '%Y-%m-%d') except ValueError: msg = '日期必須是 ISO 格式 (yyyy-mm-dd)' raise NewsSearchException(msg) # 防止開始日期大於結束日期 if self.params['beg_date'] is not None: delta = self.params['end_date'] - self.params['beg_date'] if delta.days < 0: msg = '開始日期必須小於或等於結束日期' raise NewsSearchException(msg) if delta.days > 90 and channel == 'ltn': msg = '頻道 {} 的日期條件必須在 90 天內'.format(channel) raise NewsSearchException(msg) self.conf = twnews.common.get_channel_conf(channel, 'search') self.context = None self.result = { 'pages': 0, 'elapsed': 0, 'items': [] } self.url_prefix = { 'host': '', 'base': '' } def by_keyword(self, keyword, title_only=False): """ 關鍵字搜尋 """ # pylint: disable=fixme logger = twnews.common.get_logger() page = 1 results = [] no_more = False begin_time = time.time() # 如果蘋果和自由以外的媒體有設定日期範圍,先跳到合適的頁數 # - 支援: 東森、聯合 # - 不支援: 三立、中央社 # TODO: 三立、中央社研擬假設 500 頁的二分翻頁法 if self.params['beg_date'] is not None and self.params['channel'] in ['ettoday', 'udn']: # 東森、聯合採取二分翻頁法 page = self.__flip_to_end_date(keyword) while not no_more and len(results) < self.params['limit']: self.__load_page(keyword, page) # 拆查詢結果 result_nodes = self.__result_nodes() result_count = len(result_nodes) logger.info('第 %d 頁: 有 %d 筆搜尋結果', page, result_count) if result_count > 0: for node in result_nodes: date_inst = self.__parse_date_node(node) if self.params['beg_date'] is not None and \ self.params['channel'] not in ['appledaily', 'ltn']: # 過濾開頭超過日期範圍的項目 if date_inst > self.params['end_date']: continue # 過濾結尾超過日期範圍的項目 if date_inst < self.params['beg_date']: no_more = True break title = self.__parse_title_node(node) link = self.__parse_link_node(node) if (not title_only) or (keyword in title): results.append({ "title": title, "link": link, 'date': date_inst }) if len(results) == self.params['limit']: break else: no_more = True page += 1 self.result = { 'pages': page - 1, 'elapsed': time.time() - begin_time, 'items': filter_duplicated(results) } return self def to_dict_list(self): """ 回傳新聞查詢結果 """ return self.result['items'] def to_soup_list(self): """ 回傳新聞查詢結果的分解器 """ soup_list = [] for result in self.result['items']: nsoup = NewsSoup(result['link'], proxy_first=self.params['proxy_first']) soup_list.append(nsoup) return soup_list def elapsed(self): """ 耗費時間 """ return self.result['elapsed'] def pages(self): """ 頁數 """ return self.result['pages'] def __flip_to_end_date(self, keyword): """ 回傳篩選時間範圍的開始頁數 """ page_range = { 'lower': 1, 'upper': 1000 } date_range = { 'lower': datetime.fromtimestamp(0), 'upper': datetime.today() } # 取得最大頁數 self.__load_page(keyword, 1) node = self.context.select(self.conf['last_page'])[0] if 'page_pattern' in self.conf: match = re.search(self.conf['page_pattern'], node.text) if match: page_range['upper'] = int(match.group(1)) else: page_range['upper'] = -1 else: try: page_range['upper'] = int(node.text) except ValueError: page_range['upper'] = -1 if page_range['upper'] == -1: return 1 # 取第一則搜尋結果的日期 date_range['upper'] = self.__parse_date_node(self.__result_nodes()[0]) if date_range['upper'] < self.params['end_date']: return 1 # 取最後一頁最後一則搜尋結果的日期 self.__load_page(keyword, page_range['upper']) date_range['lower'] = self.__parse_date_node(self.__result_nodes()[-1]) if date_range['lower'] > self.params['end_date']: return -1 # 起始狀態 page_dist = page_range['upper'] - page_range['lower'] prev_dist = page_range['upper'] - page_range['lower'] + 1 logger = twnews.common.get_logger() logger.info( 'page: %d ~ %d, date: %s ~ %s', page_range['lower'], page_range['upper'], date_range['upper'], date_range['lower'] ) # 取中間頁數,檢查是否能縮小範圍 # 不能縮小範圍時,表示 page_range 的新聞都有 self.params['end_date'] 這一天的 while page_dist < prev_dist: mid_page = (page_range['lower'] + page_range['upper']) // 2 self.__load_page(keyword, mid_page) middle_udt = self.__parse_date_node(self.__result_nodes()[0]) middle_ldt = self.__parse_date_node(self.__result_nodes()[-1]) if middle_udt > self.params['end_date']: page_range['lower'] = mid_page date_range['upper'] = middle_udt if middle_ldt < self.params['end_date']: page_range['upper'] = mid_page date_range['lower'] = middle_ldt prev_dist = page_dist page_dist = page_range['upper'] - page_range['lower'] logger.info( 'page: %d ~ %d, date: %s ~ %s, mid=%d', page_range['lower'], page_range['upper'], date_range['upper'], date_range['lower'], mid_page ) return page_range['lower'] def __load_page(self, keyword, page): # pylint: disable=fixme # 組查詢條件 replacement = { 'PAGE': page, 'KEYWORD': urllib.parse.quote_plus(keyword) } url = Template(self.conf['url']).substitute(replacement) # 再加上日期範圍 if self.params['beg_date'] is not None and self.params['channel'] in ['appledaily', 'ltn']: url += self.params['beg_date'].strftime(self.conf['begin_date_format']) url += self.params['end_date'].strftime(self.conf['end_date_format']) # 查詢 session = twnews.common.get_session(proxy_first=self.params['proxy_first']) logger = twnews.common.get_logger() logger.info('新聞搜尋 %s', url) resp = session.get(url, allow_redirects=False) if resp.status_code == 200: logger.debug('回應 200 OK') ctype = resp.headers['Content-Type'] if 'text/html' in ctype: self.context = BeautifulSoup(resp.text, 'lxml') if 'application/json' in ctype: # TODO: 這裡有時會發生 decode error self.context = resp.json() elif resp.status_code == 404: logger.debug('回應 404 Not Found,視為沒有更多查詢結果') self.context = None else: logger.warning('回應碼: %s', resp.status_code) self.context = None def __result_nodes(self): """ 取查詢結果的 soup 或 dict """ if self.context is not None: if isinstance(self.context, BeautifulSoup): return self.context.select(self.conf['result_node']) return visit_dict(self.context, self.conf['result_node']) return [] def __parse_title_node(self, result_node): """ 單筆查詢結果範圍內取標題文字 """ if isinstance(result_node, Tag): title_node = result_node.select(self.conf['title_node'])[0] title = title_node.text.strip() else: title = visit_dict(result_node, self.conf['title_node']) return title def __parse_date_node(self, result_node): """ 單筆查詢結果範圍內取報導日期 """ if isinstance(result_node, Tag): date_node = result_node.select(self.conf['date_node'])[0] if 'date_pattern' in self.conf: # DOM node 除了日期還有其他文字 match = re.search(self.conf['date_pattern'], date_node.text) date_text = match.group(0) else: # DOM node 只有日期 date_text = date_node.text.strip() else: # API 的日期都很乾淨 date_text = visit_dict(result_node, self.conf['date_node']) date_inst = datetime.strptime(date_text, self.conf['date_format']) return date_inst def __parse_link_node(self, result_node): """ 單筆查詢結果範圍內取新聞連結 """ if isinstance(result_node, Tag): link_node = result_node.select(self.conf['link_node'])[0] href = link_node['href'] else: href = visit_dict(result_node, self.conf['link_node']) # 完整網址 if href.startswith('https://'): return href # 絕對路徑 if href.startswith('/'): if self.url_prefix['host'] == '': match = re.match(r'^https://([^/]+)/', self.conf['url']) self.url_prefix['host'] = match.group(1) return 'https://{}{}'.format(self.url_prefix['host'], href) # 相對路徑 # 自由的 有設定 base_url if self.url_prefix['base'] == '': nodes = self.context.select('head > base') if len(nodes) == 1: self.url_prefix['base'] = nodes[0]['href'] else: base_end = self.conf['url'].rfind('/') self.url_prefix['base'] = self.conf['url'][0:base_end+1] full_url = self.url_prefix['base'] + href # 消除三立的 ../ # 這段 code 已知在 windows 會出現 C:\ 在網址中間 (Issue #93) # 原因是 os.path.realpath() 在 windows 上會出現 C:\ # 目前暫時先不處理 ../ 問題, 之後如果再發生, 需要改用替代方法 #spos = full_url.find('/', 10) #reduced_url = full_url[0:spos] + os.path.realpath(full_url[spos:]) #return reduced_url return full_url ================================================ FILE: twnews/soup.py ================================================ """ 新聞分解模組 """ import io import re import copy import lzma import hashlib import os import os.path from datetime import datetime import requests import requests.exceptions from bs4 import BeautifulSoup import twnews.common def get_cache_filepath(channel, uri): """ 取得快取檔案路徑 """ cache_id = hashlib.md5(uri.encode('ascii')).hexdigest() path = '{}/{}.html.xz'.format(twnews.common.get_cache_dir(channel), cache_id) return path def url_follow_redirection(url, proxy_first): """ 取得轉址後的 URL """ logger = twnews.common.get_logger() session = twnews.common.get_session(proxy_first) old_url = url new_url = '' done = False while not done: try: resp = session.head(old_url) status = resp.status_code if status in (301, 302): dest = resp.headers['Location'] if dest.startswith('//'): new_url = 'https:' + dest elif dest.startswith('/'): new_url = old_url[0:old_url.find('/', 10)] + dest else: new_url = dest logger.debug('===== 轉址細節 =====') logger.debug('HTTP Status: %d', status) logger.debug('Location: %s', dest) logger.debug('原始 URL: %s', old_url) logger.debug('變更 URL: %s', new_url) logger.debug('====================') old_url = new_url elif status == 200: done = True else: logger.error('檢查轉址過程發生錯誤') logger.error('HTTP Status: %d,', status) logger.error('URL: %s,', old_url) done = True except requests.exceptions.ConnectionError as ex: logger.error('檢查轉址過程連線失敗: %s', ex) done = True return old_url def url_force_https(url): """ 強制使用 https """ logger = twnews.common.get_logger() if url.startswith('http://'): new_url = 'https://' + url[7:] logger.debug('原始 URL: %s', url) logger.debug('變更 URL: %s', new_url) else: new_url = url # 蘋果地產例外,要喬回來 if new_url.startswith('https://home.appledaily.com.tw'): new_url = 'http://home.appledaily.com.tw' + new_url[30:] return new_url def url_force_ltn_mobile(url): """ 強制使用自由時報行動版 """ logger = twnews.common.get_logger() new_url = url sub_chanels = r'^https://(3c|auto|ec|ent|food|istyle|market|playing|sports).ltn.com.tw/[^m].+' if url.startswith('https://news.ltn.com.tw'): new_url = 'https://m.ltn.com.tw' + url[len('https://news.ltn.com.tw'):] logger.debug('原始 URL: %s', url) logger.debug('變更 URL: %s', new_url) elif re.match(sub_chanels, url): uri_pos = url.find('/', 10) new_url = url[:uri_pos] + '/m' + url[uri_pos:] logger.debug('原始 URL: %s', url) logger.debug('變更 URL: %s', new_url) return new_url def soup_from_website(url, channel, refresh, proxy_first): """ 網址轉換成 BeautifulSoup 4 物件 """ logger = twnews.common.get_logger() session = twnews.common.get_session(proxy_first) # 嘗試使用快取 soup = None rawlen = 0 uri = url[url.find('/', 10):] path = get_cache_filepath(channel, uri) if os.path.isfile(path) and not refresh: logger.debug('發現快取, URL: %s', url) logger.debug('載入快取, PATH: %s', path) (soup, rawlen) = soup_from_file(path) # 下載網頁 if soup is None: logger.debug('GET URL: %s', url) try: resp = session.get(url, allow_redirects=False) if resp.status_code == 200: logger.debug('回應 200 OK') if resp.headers['content-type'].find('charset=') == -1: # #80: 蘋果日報主頻道 Content-Type: text/html # 因為沒有指定編碼造成 requests 誤判, 使用小伎倆迴避 content = resp.content.decode('utf-8') else: content = resp.text soup = BeautifulSoup(content, 'lxml') rawlen = len(resp.text.encode('utf-8')) with lzma.open(path, 'wt') as cache_file: logger.debug('寫入快取: %s', path) cache_file.write(content) else: logger.warning('回應碼: %d', resp.status_code) except requests.exceptions.ConnectionError as ex: logger.error('連線失敗: %s', ex) return (soup, rawlen) def soup_from_file(file_path): """ 本地檔案轉換成 BeautifulSoup 4 物件 """ html = None soup = None clen = 0 if file_path.endswith('.xz'): with lzma.open(file_path, 'rt') as cache_file: html = cache_file.read() else: with open(file_path, 'rt') as cache_file: html = cache_file.read() if html is not None: soup = BeautifulSoup(html, 'lxml') clen = len(html.encode('utf-8')) return (soup, clen) def scan_author(article): """ 從新聞內文找出記者姓名 """ patterns = [ (r'(記者|中心)(\w{2,5})[//╱](.+報導|特稿)', 2), (r'文[//╱]記者(\w{2,5})', 1), (r'[\((](\w{2,5})[//╱].+報導[\))]', 1), (r'記者(\w{2,3}).{2}[縣市]?\d{1,2}日電', 1), (r'(記者|遊戲角落 )(\w{2,5})$', 2), (r'\s(\w{2,5})[//╱].+報導$', 1), (r'(譯者:(\w{2,5})/.+)', 1), (r'【(\w{2,5})╱.+報導】', 1) ] exclude_list = [ '國際中心', '地方中心', '社會中心', '攝影' ] for (patt, gidx) in patterns: pobj = re.compile(patt) match = pobj.search(article) if match is not None: if match.group(1) not in exclude_list: return match.group(gidx) return None class NewsSoup: """ 新聞分解器 """ # pylint: disable=too-many-instance-attributes def __init__(self, path, refresh=False, proxy_first=False): """ 建立新聞分解器 """ self.path = path self.refresh = refresh self.proxy_first = proxy_first self.loaded = False self.soup = None self.rawlen = 0 self.logger = twnews.common.get_logger() self.channel = twnews.common.detect_channel(path) self.cache = { 'title': None, 'date_raw': None, 'date': None, 'author': None, 'contents': None, 'tags': None } if self.channel == '': self.logger.error('不支援的新聞台,請檢查設定檔') return # URL 正規化 if self.path.startswith('http'): self.path = url_follow_redirection(self.path, self.proxy_first) self.path = url_force_https(self.path) if self.channel == 'ltn': self.path = url_force_ltn_mobile(self.path) # Layout 偵測 layout = 'mobile' layout_list = twnews.common.get_channel_conf(self.channel, 'layout_list') for item in layout_list: if self.path.startswith(item['prefix']): layout = item['layout'] self.conf = twnews.common.get_channel_conf(self.channel, layout) def __get_soup(self): if not self.loaded: self.loaded = True try: if self.path.startswith('http'): self.logger.debug('從網路載入新聞') (self.soup, self.rawlen) = soup_from_website( self.path, self.channel, self.refresh, self.proxy_first ) else: self.logger.debug('從檔案載入新聞') (self.soup, self.rawlen) = soup_from_file(self.path) except requests.ConnectionError as ex: self.logger.error('因連線問題,無法載入新聞: %s', ex) self.logger.error(self.path) except FileNotFoundError as ex: self.logger.error('檔案不存在,無法載入新聞: %s', ex) self.logger.error(self.path) except TypeError as ex: self.logger.error('頻道不存在,無法載入新聞: %s', ex) self.logger.error(self.path) if self.soup is None: self.logger.error('無法轉換 BeautifulSoup,可能是網址或檔案路徑錯誤') return self.soup def title(self): """ 取得新聞標題 """ soup = self.__get_soup() if soup is None: return None if self.cache['title'] is None: nsel = self.conf['title_node'] found = soup.select(nsel) if found: node = copy.copy(found[0]) # 避免子元件干擾日期格式 for child_node in node.select('*'): child_node.extract() self.cache['title'] = node.text.strip() if len(found) > 1: self.logger.warning('找到多組標題節點 (新聞台: %s)', self.channel) else: self.logger.error('找不到標題節點 (新聞台: %s)', self.channel) return self.cache['title'] def date_raw(self): """ 取得原始時間字串 """ soup = self.__get_soup() if soup is None: return None if self.cache['date_raw'] is None: nsel = self.conf['date_node'] found = soup.select(nsel) if found: node = copy.copy(found[0]) # 中時: 日期散落在兩個子節點,不可丟棄子節點 # 聯合: 日期在這個節點,子節點有其他文字,必須丟棄子節點 if 'date_with_children' not in self.conf or not self.conf['date_with_children']: # 丟棄子節點 for child_node in node.select('*'): child_node.extract() self.cache['date_raw'] = node.text.strip() if len(found) > 1: self.logger.warning('發現多組日期節點 (新聞台: %s)', self.channel) else: self.logger.error('找不到日期時間節點 (新聞台: %s)', self.channel) return self.cache['date_raw'] def date(self): """ 取得 datetime.datetime 格式的時間 """ soup = self.__get_soup() if soup is None: return None if self.cache['date'] is None: formats = self.conf['date_format'] if isinstance(formats, str): formats = [formats] for dfmt in formats: try: self.cache['date'] = datetime.strptime(self.date_raw(), dfmt) except TypeError as ex: errmsg = '日期格式分析失敗 {} (新聞台: {})'.format(ex, self.channel) except ValueError as ex: errmsg = '日期格式分析失敗 {} (新聞台: {})'.format(ex, self.channel) if self.cache['date'] is None: self.logger.error(errmsg) return self.cache['date'] def author(self): """ 取得新聞記者/社論作者 """ # pylint: disable=too-many-branches soup = self.__get_soup() if soup is None: return None if self.cache['author'] is None: nsel = self.conf['author_node'] if nsel != '': if isinstance(nsel, str): selectors = [nsel] else: selectors = nsel for nsel in selectors: found = soup.select(nsel) if found: node = copy.copy(found[0]) for child_node in node.select('*'): child_node.extract() author_raw = node.text.strip() if author_raw[0] != '記' and len(author_raw) <= 5: self.cache['author'] = author_raw else: self.cache['author'] = scan_author(author_raw) if len(found) > 1: self.logger.warning('找到多組記者姓名 (新聞台: %s)', self.channel) break else: self.logger.warning('找不到記者節點 (新聞台: %s)', self.channel) else: contents = self.contents() if contents is not None: self.cache['author'] = scan_author(contents) if self.cache['author'] is None: self.logger.warning('內文中找不到記者姓名 (新聞台: %s)', self.channel) else: self.logger.error('因為沒有內文所以無法比對記者姓名 (新聞台: %s)', self.channel) return self.cache['author'] def contents(self, limit=0): """ 取得新聞內文 """ soup = self.__get_soup() if soup is None: return None if self.cache['contents'] is None: nsel = self.conf['article_node'] found = soup.select(nsel) if found: contents = io.StringIO() for node in found: contents.write(node.text.strip()) self.cache['contents'] = contents.getvalue() contents.close() else: self.logger.error('找不到內文節點 (新聞台: %s)', self.channel) if isinstance(self.cache['contents'], str) and limit > 0: # https://github.com/PyCQA/pylint/issues/1498 # pylint: disable=unsubscriptable-object return self.cache['contents'][0:limit] return self.cache['contents'] def effective_text_rate(self): """ 計算有效內容率 (有效內容位元組數/全部位元組數) """ soup = self.__get_soup() if soup is None or self.rawlen == 0: return 0 data = [ self.title(), self.author(), self.date_raw(), self.contents() ] useful_len = 0 for datum in data: if datum is not None: useful_len += len(datum.encode('utf-8')) return useful_len / self.rawlen ================================================ FILE: twnews/tests/__init__.py ================================================ ================================================ FILE: twnews/tests/search/__init__.py ================================================ ================================================ FILE: twnews/tests/search/test_search_appledaily.py ================================================ """ 蘋果日報搜尋測試 """ import unittest from twnews.search import NewsSearch #@unittest.skip class TestAppleDaily(unittest.TestCase): """ 蘋果日報搜尋測試 """ def setUp(self): self.keyword = '上吊' self.nsearch = NewsSearch('appledaily', limit=10) def test_01_filter_title(self): """ 測試蘋果日報搜尋 """ results = self.nsearch.by_keyword(self.keyword, title_only=True).to_dict_list() for topic in results: if '上吊' not in topic['title']: self.fail('標題必須含有 "上吊"') def test_02_search_and_soup(self): """ 測試蘋果日報搜尋+分解 """ nsoups = self.nsearch.by_keyword(self.keyword).to_soup_list() for nsoup in nsoups: if nsoup.contents() is None: # 因為 home.appledaily.com.tw 的 SSL 憑證有問題,忽略這個因素造成的錯誤 if not nsoup.path.startswith('https://home.appledaily.com.tw'): msg = '內文不可為 None, URL={}'.format(nsoup.path) self.fail(msg) ================================================ FILE: twnews/tests/search/test_search_cna.py ================================================ """ 中央社搜尋測試 """ import unittest from twnews.search import NewsSearch #@unittest.skip class TestCna(unittest.TestCase): """ 中央社搜尋測試 """ def setUp(self): self.keyword = '上吊' self.nsearch = NewsSearch('cna', limit=10) def test_01_filter_title(self): """ 測試中央社搜尋 """ results = self.nsearch.by_keyword(self.keyword, title_only=True).to_dict_list() for topic in results: if '上吊' not in topic['title']: self.fail('標題必須含有 "上吊"') def test_02_search_and_soup(self): """ 測試中央社搜尋+分解 """ nsoups = self.nsearch.by_keyword(self.keyword).to_soup_list() for nsoup in nsoups: if nsoup.contents() is None: self.fail('內文不可為 None') ================================================ FILE: twnews/tests/search/test_search_ettoday.py ================================================ """ 東森新聞雲搜尋測試 """ import unittest from twnews.search import NewsSearch #@unittest.skip class TestEttoday(unittest.TestCase): """ 東森新聞雲搜尋測試 """ def setUp(self): self.keyword = '上吊' self.nsearch = NewsSearch('ettoday', limit=10, proxy_first=True) def test_01_filter_title(self): """ 測試東森新聞雲搜尋 """ results = self.nsearch.by_keyword(self.keyword, title_only=True).to_dict_list() for topic in results: if '上吊' not in topic['title']: self.fail('標題必須含有 "上吊"') def test_02_search_and_soup(self): """ 測試東森新聞雲搜尋+分解 """ nsoups = self.nsearch.by_keyword(self.keyword).to_soup_list() for nsoup in nsoups: if nsoup.contents() is None: msg = '內文不可為 None, URL={}'.format(nsoup.path) self.fail(msg) ================================================ FILE: twnews/tests/search/test_search_ltn.py ================================================ """ 自由時報搜尋測試 """ import unittest from twnews.search import NewsSearch #@unittest.skip class TestLtn(unittest.TestCase): """ 自由時報搜尋測試 """ def setUp(self): self.keyword = '上吊' self.nsearch = NewsSearch('ltn', limit=10) def test_01_filter_title(self): """ 測試自由時報搜尋 """ results = self.nsearch.by_keyword(self.keyword, title_only=True).to_dict_list() for topic in results: if '上吊' not in topic['title']: self.fail('標題必須含有 "上吊"') def test_02_search_and_soup(self): """ 測試自由時報搜尋+分解 """ nsoups = self.nsearch.by_keyword(self.keyword).to_soup_list() for nsoup in nsoups: if nsoup.contents() is None: self.fail('內文不可為 None') ================================================ FILE: twnews/tests/search/test_search_setn.py ================================================ """ 三立新聞網搜尋測試 """ import unittest from twnews.search import NewsSearch #@unittest.skip class TestSetn(unittest.TestCase): """ 三立新聞網搜尋測試 """ def setUp(self): self.keyword = '上吊' self.nsearch = NewsSearch('setn', limit=10) def test_01_filter_title(self): """ 測試三立新聞網搜尋 """ results = self.nsearch.by_keyword(self.keyword, title_only=True).to_dict_list() for topic in results: if '上吊' not in topic['title']: self.fail('標題必須含有 "上吊"') def test_02_search_and_soup(self): """ 測試三立新聞網搜尋+分解 """ nsoups = self.nsearch.by_keyword(self.keyword).to_soup_list() for nsoup in nsoups: if nsoup.contents() is None: self.fail('內文不可為 None') ================================================ FILE: twnews/tests/search/test_search_udn.py ================================================ """ 聯合新聞網搜尋測試 """ import unittest from twnews.search import NewsSearch #@unittest.skip class TestUdn(unittest.TestCase): """ 聯合新聞網搜尋測試 """ def setUp(self): self.keyword = '上吊' self.nsearch = NewsSearch('udn', limit=10) def test_01_filter_title(self): """ 測試聯合新聞網搜尋 """ results = self.nsearch.by_keyword(self.keyword, title_only=True).to_dict_list() for topic in results: if '上吊' not in topic['title']: self.fail('標題必須含有 "上吊"') def test_02_search_and_soup(self): """ 測試聯合新聞網搜尋+分解 """ nsoups = self.nsearch.by_keyword(self.keyword).to_soup_list() for nsoup in nsoups: if nsoup.title() is None: self.fail('標題不可為 None') ================================================ FILE: twnews/tests/soup/__init__.py ================================================ ================================================ FILE: twnews/tests/soup/test_soup_appledaily.py ================================================ """ 蘋果日報分解測試 """ # pylint: disable=duplicate-code import unittest import twnews.common from twnews.soup import NewsSoup #@unittest.skip class TestAppleDaily(unittest.TestCase): """ 蘋果日報分解測試 """ def setUp(self): self.dtf = '%Y-%m-%d %H:%M:%S' def test_01_sample(self): """ 測試蘋果日報樣本 """ pkgdir = twnews.common.get_package_dir() nsoup = NewsSoup(pkgdir + '/samples/appledaily.html.xz') self.assertEqual('appledaily', nsoup.channel) self.assertIn('和男友口角鎖門吞藥 女墜樓不治', nsoup.title()) self.assertEqual('2016-05-21 11:44:00', nsoup.date().strftime(self.dtf)) self.assertEqual('王煌忠', nsoup.author()) self.assertIn('文心路的一棟住宅大樓', nsoup.contents()) def test_02_mobile(self): """ 測試蘋果日報行動版 """ url = 'https://tw.news.appledaily.com/local/realtime/20181025/1453825' nsoup = NewsSoup(url, refresh=True) self.assertEqual('appledaily', nsoup.channel) self.assertIn('男子疑久病厭世 學校圍牆上吊輕生亡', nsoup.title()) self.assertEqual('2018-10-25 12:03:00', nsoup.date().strftime(self.dtf)) self.assertEqual('江宏倫', nsoup.author()) self.assertIn('台北市北投區西安街二段', nsoup.contents()) def test_03_layouts(self): """ 測試蘋果地產 """ layouts = [ { 'url': 'http://home.appledaily.com.tw/article/index/20190313/38279127', 'title': '潮牌概念店撤離 東區房東陷定位危機', 'date': '2019-03-13 00:00:00', 'author': '唐家儀', 'contents': '英國人氣潮牌Superdry(超級乾燥)位大安區忠孝東路四段的形象概念門市竟已歇業' } ] for layout in layouts: nsoup = NewsSoup(layout['url'], refresh=True, proxy_first=True) self.assertEqual('appledaily', nsoup.channel) self.assertIn(layout['title'], nsoup.title()) if nsoup.date() is not None: self.assertEqual(layout['date'], nsoup.date().strftime(self.dtf)) else: self.assertEqual(layout['date'], nsoup.date()) self.assertEqual(layout['author'], nsoup.author()) self.assertIn(layout['contents'], nsoup.contents()) ================================================ FILE: twnews/tests/soup/test_soup_chinatimes.py ================================================ """ 中時電子報分解測試 """ # pylint: disable=duplicate-code import unittest import twnews.common from twnews.soup import NewsSoup #@unittest.skip class TestChinatimes(unittest.TestCase): """ 中時電子報分解測試 """ def setUp(self): self.url = 'https://www.chinatimes.com/realtimenews/20180916001767-260402' self.dtf = '%Y-%m-%d %H:%M:%S' def test_01_sample(self): """ 測試中時電子報樣本 """ pkgdir = twnews.common.get_package_dir() nsoup = NewsSoup(pkgdir + '/samples/chinatimes.html.xz') self.assertEqual('chinatimes', nsoup.channel) self.assertIn('悲慟!北市士林年邁母子 住處上吊自殺身亡', nsoup.title()) self.assertEqual('2018-09-16 15:31:00', nsoup.date().strftime(self.dtf)) self.assertEqual('謝明俊', nsoup.author()) self.assertIn('北市士林區葫蘆街一處民宅', nsoup.contents()) def test_02_mobile(self): """ 測試中時電子報行動版 """ nsoup = NewsSoup(self.url, refresh=True) self.assertEqual('chinatimes', nsoup.channel) self.assertIn('悲慟!北市士林年邁母子 住處上吊自殺身亡', nsoup.title()) self.assertEqual('2018-09-16 15:31:00', nsoup.date().strftime(self.dtf)) self.assertEqual('謝明俊', nsoup.author()) self.assertIn('北市士林區葫蘆街一處民宅', nsoup.contents()) ================================================ FILE: twnews/tests/soup/test_soup_cna.py ================================================ """ 中央社分解測試 """ # pylint: disable=duplicate-code import unittest import twnews.common from twnews.soup import NewsSoup #@unittest.skip class TestCna(unittest.TestCase): """ 中央社分解測試 """ def setUp(self): self.url = 'https://www.cna.com.tw/news/asoc/201810170077.aspx' self.dtf = '%Y-%m-%d %H:%M:%S' def test_01_sample(self): """ 測試中央社樣本 """ pkgdir = twnews.common.get_package_dir() nsoup = NewsSoup(pkgdir + '/samples/cna.html.xz') self.assertEqual('cna', nsoup.channel) self.assertIn('平鎮輪胎行惡火 疏散7人1女命喪', nsoup.title()) self.assertEqual('2016-03-19 10:48:00', nsoup.date().strftime(self.dtf)) self.assertEqual('邱俊欽', nsoup.author()) self.assertIn('桃園市平鎮區一家輪胎行', nsoup.contents()) def test_02_mobile(self): """ 測試中央社行動版 """ nsoup = NewsSoup(self.url, refresh=True) self.assertEqual('cna', nsoup.channel) self.assertIn('前女友輕生 前男友到殯儀館砍現任還開槍', nsoup.title()) self.assertEqual('2018-10-17 14:06:00', nsoup.date().strftime(self.dtf)) self.assertEqual('黃國芳', nsoup.author()) self.assertIn('民主進步黨籍嘉義市議員王美惠上午到殯儀館參加公祭', nsoup.contents()) ================================================ FILE: twnews/tests/soup/test_soup_common.py ================================================ """ 分解共用程式測試 為了節省爬蟲開發時間,原則上 NewsSoup 盡量不丟例外,有問題以 logging 機制為主 """ # pylint: disable=wildcard-import,unused-wildcard-import import os import unittest import twnews.common from twnews.soup import * class TestCommon(unittest.TestCase): """ 不分頻道分解測試 """ def setUp(self): self.url = 'https://tw.appledaily.com/headline/daily/20181201/38194705/' self.dtf = '%Y-%m-%d %H:%M:%S' def test_01_cache(self): """ 測試快取機制 """ # 清除快取 cache_dir = twnews.common.get_cache_dir('appledaily') cache_path = '{}/ed33e11740a7c95cb0852827b91cd37d.html.xz'.format(cache_dir) if os.path.isfile(cache_path): os.unlink(cache_path) # 讀取新聞,計算快取檔案數 NewsSoup(self.url).title() has_cache = os.path.isfile(cache_path) self.assertTrue(has_cache) # 再次讀取新聞,確認快取檔的 mtime 沒變 if has_cache: news_mtime_old = os.path.getmtime(cache_path) NewsSoup(self.url).title() news_mtime_new = os.path.getmtime(cache_path) self.assertEqual(news_mtime_old, news_mtime_new) def test_02_soup_from_website(self): ''' 測試 NewSoup(URL) 輸入不理想網址 ''' # pylint: disable=broad-except, line-too-long # channel 不存在 try: nsoup = NewsSoup('https://localhost.xxx') self.assertIsNone(nsoup.title(), 'channel 錯誤時,title() 應該回傳 None') self.assertIsNone(nsoup.date(), 'channel 錯誤時,date() 應該回傳 None') self.assertIsNone(nsoup.author(), 'channel 錯誤時,author() 應該回傳 None') self.assertIsNone(nsoup.contents(), 'channel 錯誤時,contents() 應該回傳 None') self.assertEqual(0, nsoup.effective_text_rate(), 'channel 錯誤時,effective_text_rate() 應該回傳 0') except Exception: self.fail('channel 錯誤時,__init__() 不應該發生例外') # channel 正確但 host 漏字 try: nsoup = NewsSoup('https://appledaily.co') self.assertIsNone(nsoup.title(), 'host 錯誤時,title() 應該回傳 None') self.assertIsNone(nsoup.date(), 'host 錯誤時,date() 應該回傳 None') self.assertIsNone(nsoup.author(), 'host 錯誤時,author() 應該回傳 None') self.assertIsNone(nsoup.contents(), 'host 錯誤時,contents() 應該回傳 None') self.assertEqual(0, nsoup.effective_text_rate(), 'host 錯誤時,effective_text_rate() 應該回傳 0') except Exception: self.fail('host 錯誤時,__init__() 不應該發生例外') # host 正確但 url 漏字 try: url = 'https://tw.news.appledaily.com/local/realtime/WRONG/NEWS_ID' nsoup = NewsSoup(url) self.assertIsNone(nsoup.title(), 'url 錯誤時,title() 應該回傳 None') self.assertIsNone(nsoup.date(), 'url 錯誤時,date() 應該回傳 None') self.assertIsNone(nsoup.author(), 'url 錯誤時,author() 應該回傳 None') self.assertIsNone(nsoup.contents(), 'url 錯誤時,contents() 應該回傳 None') self.assertEqual(0, nsoup.effective_text_rate(), '頻道錯誤時,effective_text_rate() 應該回傳 0') except Exception: self.fail('url 錯誤時,__init__() 不應該發生例外') def test_03_soup_from_file(self): ''' 測試 NewsSoup(FILE) 輸入不理想檔案 ''' # pylint: disable=broad-except, line-too-long # channel 不存在 try: nsoup = NewsSoup('/tmp/badchannel.html') self.assertIsNone(nsoup.title(), 'channel 錯誤時,title() 應該回傳 None') self.assertIsNone(nsoup.date(), 'channel 錯誤時,date() 應該回傳 None') self.assertIsNone(nsoup.author(), 'channel 錯誤時,author() 應該回傳 None') self.assertIsNone(nsoup.contents(), 'channel 錯誤時,contents() 應該回傳 None') self.assertEqual(0, nsoup.effective_text_rate(), 'channel 錯誤時,effective_text_rate() 應該回傳 0') except Exception: self.fail('channel 錯誤時,__init__() 不應該發生例外') # 檔案不存在 try: nsoup = NewsSoup('/tmp/appledaily-notexisted.html') self.assertIsNone(nsoup.title(), '檔案不存在時,title() 應該回傳 None') self.assertIsNone(nsoup.date(), '檔案不存在時,date() 應該回傳 None') self.assertIsNone(nsoup.author(), '檔案不存在時,author() 應該回傳 None') self.assertIsNone(nsoup.contents(), '檔案不存在時,contents() 應該回傳 None') self.assertEqual(0, nsoup.effective_text_rate(), '檔案不存在時,effective_text_rate() 應該回傳 0') except Exception: self.fail('檔案不存在時,__init__() 不應該發生例外') # 空白檔案 try: open('appledaily-empty.html', 'a').close() nsoup = NewsSoup('appledaily-empty.html') self.assertIsNone(nsoup.title(), '空白檔案時,title() 應該回傳 None') self.assertIsNone(nsoup.date(), '空白檔案時,date() 應該回傳 None') self.assertIsNone(nsoup.author(), '空白檔案時,author() 應該回傳 None') self.assertIsNone(nsoup.contents(), '空白檔案時,contents() 應該回傳 None') self.assertEqual(0, nsoup.effective_text_rate(), '檔案不存在時,effective_text_rate() 應該回傳 0') os.unlink('appledaily-empty.html') except Exception: self.fail('空白檔案時,__init__() 不應該發生例外') # 空白 gz 檔案 try: open('appledaily-empty.html.gz', 'a').close() nsoup = NewsSoup('appledaily-empty.html') self.assertIsNone(nsoup.soup) self.assertIsNone(nsoup.title(), '空白檔案時,title() 應該回傳 None') self.assertIsNone(nsoup.date(), '空白檔案時,date() 應該回傳 None') self.assertIsNone(nsoup.author(), '空白檔案時,author() 應該回傳 None') self.assertIsNone(nsoup.contents(), '空白檔案時,contents() 應該回傳 None') self.assertEqual(0, nsoup.effective_text_rate(), '檔案不存在時,effective_text_rate() 應該回傳 0') os.unlink('appledaily-empty.html.gz') except Exception: self.fail('空白檔案時,__init__() 不應該發生例外') def test_04_author_in_contents(self): """ 測試無記者欄的記者姓名分析 (蘋果、中央社、東森、自由、三立) """ good_samples = [ # 蘋果 '(王覺一/台北報導)', '(林文彬/綜合外電報導)', # 中央社 '(中央社記者吳睿騏桃園5日電)', '(中央社記者黃國芳嘉義縣17日電)', '(中央社東京5日綜合外電報導)日本軟銀(譯者:何宏儒/核稿:劉學源)', # 東森 '記者吳奕靖/高雄報導', # 自由 '〔記者梁偉銘/台北報導〕', '[記者江志雄/宜蘭報導]', # 三立 '記者於慶璇/台中報導' ] bad_samples = [ # 蘋果 '(國際中心/綜合外電報導)', # 中央社 '(中央社伊斯坦堡/日內瓦5日綜合外電報導)', # 東森 '地方中心/嘉義報導', # 自由 '〔即時新聞/綜合報導〕', # 三立 '社會中心/綜合報導', # 腦補 '(地方中心/綜合報導)', '(社會中心/綜合報導)', '〔地方中心/綜合報導〕', '〔社會中心/綜合報導〕', ] for text in good_samples: author = scan_author(text) msg = '"{}" 應該分析出記者姓名'.format(text) self.assertIsNotNone(author, msg) for text in bad_samples: author = scan_author(text) msg = '"{}" 不應分析出記者姓名'.format(text) self.assertIsNone(author, msg) def test_05_author_in_node(self): """ 測試有記者欄的記者姓名分析 (中時、聯合) """ # 中時找不到異常案例,暫不測試 bad_samples = [ # 中央社 高雄6日電 (無連結) 'https://udn.com/news/story/10958/3465283', # 聯合新聞網 綜合報導 (無連結) 'https://udn.com/news/story/10958/3465161' ] for url in bad_samples: nsoup = NewsSoup(url) author = nsoup.author() msg = '"{}" 不應分析出記者姓名'.format(url) self.assertIsNone(author, msg) ================================================ FILE: twnews/tests/soup/test_soup_ettoday.py ================================================ """ 東森新聞雲分解測試 """ # pylint: disable=duplicate-code import unittest import twnews.common from twnews.soup import NewsSoup class TestEttoday(unittest.TestCase): """ 東森新聞雲分解測試 """ def setUp(self): self.dtf = '%Y-%m-%d %H:%M:%S' def test_01_sample(self): """ 測試東森新聞雲樣本 """ pkgdir = twnews.common.get_package_dir() nsoup = NewsSoup(pkgdir + '/samples/ettoday.html.xz') self.assertEqual('ettoday', nsoup.channel) self.assertIn('客運司機車禍致人於死 心情鬱悶陽台以狗鍊上吊', nsoup.title()) self.assertEqual('2017-12-09 00:26:00', nsoup.date().strftime(self.dtf)) self.assertEqual('林悅', nsoup.author()) self.assertIn('台南市永康區永安路住處後陽台上吊', nsoup.contents()) def test_02_mobile(self): """ 測試東森新聞雲 """ url = 'https://www.ettoday.net/news/20181020/1285826.htm' nsoup = NewsSoup(url, refresh=True, proxy_first=True) self.assertEqual('ettoday', nsoup.channel) self.assertIn('快訊/整日沒出房門!三重無業男半夜住處2樓上吊 母開門才發現', nsoup.title()) self.assertEqual('2018-10-20 04:11:00', nsoup.date().strftime(self.dtf)) self.assertEqual('趙永博', nsoup.author()) self.assertIn('新北市三重區三和路三段101巷一處民宅2樓', nsoup.contents()) def test_03_layouts(self): """ 測試東森新聞雲其他排版 """ layouts = [ { 'url': 'https://fashion.ettoday.net/news/1316942', 'title': '漫長的冬日夜晚想閱讀 不妨參考誠品2018年度暢銷書單', 'date': '2018-11-28 10:10:00', 'author': '蔡惠如', 'contents': '我輩中人:寫給中年人的情書' }, { 'url': 'https://game.ettoday.net/article/1315167.htm', 'title': '網石與DC聯名合作 《蝙蝠俠》角色進駐《天堂2 革命》', 'date': '2018-11-24 23:59:00', 'author': None, 'contents': '天堂2:革命' }, { 'url': 'https://health.ettoday.net/news/1317507', 'title': '謝碧珠/沒有自費就醫資訊的健康存摺很空心', 'date': '2018-11-28 12:50:00', 'author': None, 'contents': '全民健康保險法' }, { 'url': 'https://house.ettoday.net/news/1317619', 'title': '台北、新北26.1%潛勢區 「市民生命安全」柯P、漢子準備好了嗎?', 'date': '2018-11-28 11:16:00', 'author': '陳韋帆', 'contents': '其中「山腳斷層」更跨越了金山、三芝、淡水、五股、泰山、新莊及樹林等各區' }, { 'url': 'https://pets.ettoday.net/news/1307563', 'title': '去睡覺囉! 傑克羅素㹴秒轉身「抱大狗娃娃」踏踏進房:晚安~', 'date': '2018-11-16 14:50:00', 'author': '陳靜', 'contents': '每天晚上都一定要帶著它睡覺,有時候突然想到也會馬上衝進房間' }, { 'url': 'https://speed.ettoday.net/news/1316854', 'title': '休旅車&轎車誰安全?數據顯示這種車「死亡率低一半」', 'date': '2018-11-27 20:03:00', 'author': None, 'contents': '發生各類車禍事故時,普通轎車乘客死亡率為39%,而SUV只有21%' }, { 'url': 'https://sports.ettoday.net/news/1317313', 'title': '日職/丸佳浩MVP二連霸 山川穗高獲獎喊目標50轟', 'date': '2018-11-27 21:10:00', 'author': '楊舒帆', 'contents': '今年繳出打擊率0.306、39轟、97分打點的成績' }, { 'url': 'https://star.ettoday.net/news/1308844', 'title': 'KID半夜突襲女神房間! 驚見「浴衣脫落門外」他狂喜衝進去', 'date': '2018-11-17 16:40:00', 'author': '劉宜庭', 'contents': 'KID親睹這一幕,更是興奮到整個人趴在地上' }, { 'url': 'https://travel.ettoday.net/article/1317664.htm', 'title': '普羅旺斯花海、《鬼怪》蕎麥花!「全台5大花海」超醉心', 'date': '2018-11-28 12:30:00', 'author': None, 'contents': '粉紅波斯菊、向日葵、百合、鼠尾草、貓尾花、麒麟菊、雞冠花、鳳仙花等陸續盛開' } ] for layout in layouts: nsoup = NewsSoup(layout['url'], refresh=True, proxy_first=True) self.assertEqual('ettoday', nsoup.channel) self.assertIn(layout['title'], nsoup.title()) self.assertEqual(layout['date'], nsoup.date().strftime(self.dtf)) self.assertEqual(layout['author'], nsoup.author()) self.assertIn(layout['contents'], nsoup.contents()) ================================================ FILE: twnews/tests/soup/test_soup_ltn.py ================================================ """ 自由時報單元分解測試 """ # pylint: disable=duplicate-code import unittest import twnews.common from twnews.soup import NewsSoup #@unittest.skip class TestLtn(unittest.TestCase): """ 自由時報單元分解測試 """ def setUp(self): self.dtf = '%Y-%m-%d %H:%M:%S' def test_01_sample(self): """ 測試自由時報樣本 """ pkgdir = twnews.common.get_package_dir() nsoup = NewsSoup(pkgdir + '/samples/ltn.html.xz') self.assertEqual('ltn', nsoup.channel) self.assertIn('10年前父親掐死兒後自縊... 凶宅下月拍開價425萬', nsoup.title()) self.assertEqual('2018-07-31 08:19:00', nsoup.date().strftime(self.dtf)) self.assertEqual(None, nsoup.author()) self.assertIn('台北市萬華區萬大路一帶公寓的蘇姓男子', nsoup.contents()) def test_02_mobile(self): """ 測試自由時報行動版 """ url = 'http://news.ltn.com.tw/news/society/breakingnews/2581807' nsoup = NewsSoup(url, refresh=True) self.assertEqual('ltn', nsoup.channel) self.assertIn('疑因病厭世 男子國小圖書館上吊身亡', nsoup.title()) self.assertEqual('2018-10-15 23:51:00', nsoup.date().strftime(self.dtf)) self.assertEqual(None, nsoup.author()) self.assertIn('台北市萬華區的老松國小今(15)日早上驚傳上吊輕生事件', nsoup.contents()) def test_03_layouts(self): """ 測試自由時報其他排版 """ layouts = [ # TODO: 改善作者精準度 { 'url': 'http://3c.ltn.com.tw/m/news/35179', 'title': 'iPhone XR 開箱體驗(三)!相機對比 iPhone XS、Google Pixel 3', 'date': '2018-11-28 14:08:00', 'author': '黃敬淳', 'contents': '曝光控制也是 XR 相比 iPhone 8 Plus 的主要升級點' }, # TODO: 改善日期精準度 { 'url': 'http://auto.ltn.com.tw/m/news/11334/3', 'title': '瞄準 Toyota Auris,大改款 Mazda 3 洛杉磯車展正式亮相!(內有相片集)', 'date': None, 'author': '徐煜展', 'contents': '其中新造型的 LED 尾燈組也與先前公佈的 Kai Concept 概念車相仿' }, { 'url': 'http://ec.ltn.com.tw/m/article/breakingnews/2626720', 'title': '童子賢:不要幻想東南亞是下1個中國 中國模式難複製到其他國', 'date': '2018-11-28 12:40:03', 'author': '卓怡君', 'contents': '過去20年中國在台商和全球外商打造出製造業的基礎建設' }, { 'url': 'http://ent.ltn.com.tw/m/news/breakingnews/2626753', 'title': '藍文青獨賠近5千萬 自稱 「韓國瑜鑾生兄弟」', 'date': '2018-11-28 13:05:00', 'author': '蕭宇涵', 'contents': '但吳易展以旗下公司美仕特牛排公司才剛起步' }, { 'url': 'http://estate.ltn.com.tw/article/6493', 'title': '台南新吉工業區地上權招租 提供優惠方案', 'date': '2018-11-26 18:27:00', 'author': '林耀文', 'contents': '台南市新吉工業區位於臺南市安南區、安定區交界處招商也頗為亮麗' }, { 'url': 'http://food.ltn.com.tw/m/article/8263', 'title': '菠菜影響鈣吸收?吃多了會結石?別再相信謠言了!', 'date': '2018-11-28 00:00:00', 'author': None, 'contents': '許多民眾擔心菠菜富含「草酸」,會抑制鈣質吸收' }, # TODO: 改善日期精準度 { 'url': 'http://istyle.ltn.com.tw/m/article/9168', 'title': '明星瘋這咖》張鈞甯、陳庭妮私下都揹小包!「小叮噹大袋」暫退...', 'date': None, 'author': '余崇慧', 'contents': '一頭復古味十足的劉海,帶著六、七零年代阿哥哥風格' }, { 'url': 'http://market.ltn.com.tw/m/article/5159', 'title': '2018台北國際旅展 推動原住民族文化', 'date': '2018-11-27 11:31:00', 'author': None, 'contents': '台北國際旅展設置形象館,推出全台36個部落的精彩遊程' }, { 'url': 'http://playing.ltn.com.tw/m/article/11191', 'title': '北高韓粉吃雞排囉!3千份雞排賀韓國瑜當選,今起發送到週末', 'date': '2018-11-28 00:00:00', 'author': None, 'contents': '網友打趣地解釋,原先說是900份。後來加碼至1000份' }, { 'url': 'http://sports.ltn.com.tw/m/news/breakingnews/2626821', 'title': 'MLB》王牌陣解體在即?印地安人傳更想出售鮑爾', 'date': '2018-11-28 14:21:00', 'author': None, 'contents': '鮑爾目前只剩兩年控制權,而他今年有望靠著優異表現在薪資上大幅躍進' }, { 'url': 'http://talk.ltn.com.tw/article/breakingnews/2625348', 'title': '胡,怎麼說》正負8%造成政治雪崩效應', 'date': '2018-11-27 09:43:00', 'author': '胡文輝', 'contents': '2016年總統及立委選舉,民進黨才連下兩城,總統選舉得票率以56.12%狂勝國民黨的31.04%' } ] for layout in layouts: nsoup = NewsSoup(layout['url'], refresh=True, proxy_first=True) self.assertEqual('ltn', nsoup.channel) self.assertIn(layout['title'], nsoup.title()) if nsoup.date() is not None: self.assertEqual(layout['date'], nsoup.date().strftime(self.dtf)) else: self.assertEqual(layout['date'], nsoup.date()) self.assertEqual(layout['author'], nsoup.author()) self.assertIn(layout['contents'], nsoup.contents()) def test_04_switch_mobile(self): """ 測試自動切換行動版 """ url = 'http://sports.ltn.com.tw/news/breakingnews/2626821' nsoup = NewsSoup(url, refresh=True) self.assertEqual('ltn', nsoup.channel) self.assertIn('MLB》王牌陣解體在即?印地安人傳更想出售鮑爾', nsoup.title()) self.assertEqual('2018-11-28 14:21:00', nsoup.date().strftime(self.dtf)) self.assertEqual(None, nsoup.author()) self.assertIn('鮑爾目前只剩兩年控制權,而他今年有望靠著優異表現在薪資上大幅躍進', nsoup.contents()) def test_05_multiple_date_format(self): """ 測試多重日期格式 """ url = 'https://m.ltn.com.tw/news/politics/paper/1249335' nsoup = NewsSoup(url, refresh=True) self.assertEqual('ltn', nsoup.channel) self.assertIn('狂拿15席 吳總教頭首戰告捷', nsoup.title()) self.assertEqual('2018-11-25 00:00:00', nsoup.date().strftime(self.dtf)) self.assertEqual('施曉光', nsoup.author()) self.assertIn('由黨魁吳敦義扮演「總教頭」並宣稱要擊出二十二支全壘打的國民黨', nsoup.contents()) def test_06_http_redirect(self): """ 測試轉址效果 """ url = 'https://news.ltn.com.tw/news/entertainment/breakingnews/2697368' nsoup = NewsSoup(url, refresh=True) self.assertEqual('ltn', nsoup.channel) self.assertEqual('https://ent.ltn.com.tw/m/news/breakingnews/2697368', nsoup.path) self.assertIn('摸胸夾腿都來!邵翔小蠻交往6年公布「有了」', nsoup.title()) self.assertEqual('2019-02-13 11:46:00', nsoup.date().strftime(self.dtf)) self.assertEqual('蕭宇涵', nsoup.author()) self.assertIn('小蠻一席黑色小禮服大露蜜腿,雙手游移挑逗扒開邵翔的襯衫', nsoup.contents()) ================================================ FILE: twnews/tests/soup/test_soup_setn.py ================================================ """ 三立新聞網分解測試 """ # pylint: disable=duplicate-code import unittest import twnews.common from twnews.soup import NewsSoup #@unittest.skip class TestSetn(unittest.TestCase): """ 三立新聞網分解測試 """ def setUp(self): self.url = 'http://www.setn.com/News.aspx?NewsID=350370' self.dtf = '%Y-%m-%d %H:%M:%S' def test_01_sample(self): """ 測試三立新聞網樣本 """ pkgdir = twnews.common.get_package_dir() nsoup = NewsSoup(pkgdir + '/samples/setn.html.xz') self.assertEqual('setn', nsoup.channel) self.assertIn('與母爭吵疑失足墜樓 男子送醫搶救不治', nsoup.title()) self.assertEqual('2018-02-21 18:03:00', nsoup.date().strftime(self.dtf)) self.assertEqual(None, nsoup.author()) self.assertIn('新北市新店區中正路今(21)日下午3時許發生墜樓案件', nsoup.contents()) def test_02_mobile(self): """ 測試三立新聞網行動版 """ nsoup = NewsSoup(self.url, refresh=True) self.assertEqual('setn', nsoup.channel) self.assertIn('與母爭吵疑失足墜樓 男子送醫搶救不治', nsoup.title()) self.assertEqual('2018-02-21 18:03:00', nsoup.date().strftime(self.dtf)) self.assertEqual(None, nsoup.author()) self.assertIn('新北市新店區中正路今(21)日下午3時許發生墜樓案件', nsoup.contents()) def test_03_layouts(self): """ 測試三立新聞網的其他排版 """ layouts = [ { 'url': 'https://www.setn.com/e/News.aspx?NewsID=460349', 'title': '不只想贏韓國!徐展元「分手女友」紅到美國…竟是切身之痛', 'date': '2018-11-22 17:29:00', 'author': '王奕棋', 'contents': '這個球就像變了心的女朋友,回不來了' } ] for layout in layouts: nsoup = NewsSoup(layout['url'], refresh=True, proxy_first=True) self.assertEqual('setn', nsoup.channel) self.assertIn(layout['title'], nsoup.title()) self.assertEqual(layout['date'], nsoup.date().strftime(self.dtf)) self.assertEqual(layout['author'], nsoup.author()) self.assertIn(layout['contents'], nsoup.contents()) ================================================ FILE: twnews/tests/soup/test_soup_udn.py ================================================ """ 聯合新聞網分解測試 """ # pylint: disable=duplicate-code import unittest import twnews.common from twnews.soup import NewsSoup #@unittest.skip class TestUdn(unittest.TestCase): """ 聯合新聞網分解測試 """ def setUp(self): self.url = 'https://udn.com/news/story/7320/3407294' self.dtf = '%Y-%m-%d %H:%M:%S' def test_01_sample(self): """ 測試聯合新聞網樣本 """ pkgdir = twnews.common.get_package_dir() nsoup = NewsSoup(pkgdir + '/samples/udn.html.xz') self.assertEqual('udn', nsoup.channel) self.assertIn('血濺桃機 他把老婆丟下樓再跳樓', nsoup.title()) self.assertEqual('2019-03-18 23:59:00', nsoup.date().strftime(self.dtf)) self.assertEqual('陳嘉寧', nsoup.author()) self.assertIn('萬與張女站在第二航廈出境大廳管制區外南側四樓往三樓樓梯迴轉處爭吵', nsoup.contents()) def test_02_mobile(self): """ 測試聯合新聞網行動版 """ nsoup = NewsSoup(self.url, refresh=True) self.assertEqual('udn', nsoup.channel) self.assertIn('清晨起床發現父親上吊天花板 嚇壞女兒急報案', nsoup.title()) self.assertEqual('2018-10-06 15:45:00', nsoup.date().strftime(self.dtf)) self.assertEqual('陳宏睿', nsoup.author()) self.assertIn('台中市北區水源街', nsoup.contents()) def test_03_layouts(self): """ 測試聯合新聞網的其他排版 """ layouts = [ { 'url': 'https://autos.udn.com/autos/story/7826/3506163', 'title': '2018洛杉磯車展/更洗鍊有型!全新第四代Mazda3發表前廠照先曝光', 'date': '2018-11-28 11:35:11', 'author': '張振群', 'contents': 'Mazda汽車今年壓軸重頭戲全新第四代Mazda3,在正式發表前外觀定裝照率先曝光。' }, { 'url': 'https://game.udn.com/game/story/10449/3489517', 'title': '《轉校生》新手生存指南 對戰?先活下來再說吧!', 'date': '2018-11-19 17:14:00', 'author': '老宅', 'contents': '遊戲中兩大生產建設在教室下方的紙杯跟爐架,在這邊可以生產飲料跟食物' }, { 'url': 'https://global.udn.com/global_vision/story/8663/3502209', 'title': '「二次公投」好不好?凌遲式的英國脫歐單行道', 'date': '2018-11-26 00:00:00', 'author': None, 'contents': '廢除脫歐決定、舉行二次脫歐公投的聲量也越來越強' }, { 'url': 'https://health.udn.com/health/story/6037/3504950', 'title': '喝奶茶不如單喝紅茶 日本紅茶協會:加牛奶會失去兩大功效', 'date': '2018-11-28 00:41:00', 'author': '廖思涵', 'contents': '茶葉含有咖啡鹼、茶鹼、鞣酸、可可鹼、葉酸、維生素B群、C、P及少量的礦物質' }, { 'url': 'https://house.udn.com/house/story/5887/3506297', 'title': '一戶19萬也沒人要! 神才賣得掉的217戶又流標了', 'date': '2018-11-28 12:26:17', 'author': '游智文', 'contents': '北海岸喜凱亞渡假村法拍屋,今(28)日進行第17次拍賣' }, { 'url': 'https://nba.udn.com/nba/story/6780/3506854', 'title': '「鳥人」現身丹佛主場 期盼能重返NBA', 'date': '2018-11-28 16:24:00', 'author': '蔡佳霖', 'contents': '今天現身丹佛主場,在中場時間擊鼓助威,和球迷進行互動' }, { 'url': 'https://opinion.udn.com/opinion/story/12067/3506294', 'title': '從太陽花到韓流:未挑戰政經核心,只會出現鬼打牆的鐘擺效應', 'date': None, 'author': '陳柏謙', 'contents': '九合一大選結果全面潰敗,縣市首長從選前13席崩盤到僅守住6席' }, { 'url': 'https://stars.udn.com/star/story/10090/3507027', 'title': '自嘲和李進良「大餅跟鳥」 小禎妙答李婉鈺田欣誰戰力強', 'date': '2018-11-28 17:11:00', 'author': '梅衍儂', 'contents': '很心疼小禎,願意把生活裡的體驗用演技來給大家看' }, { 'url': 'https://style.udn.com/style/story/8065/3500832', 'title': '《我身後的陶斯》林世美長髮時浪漫感十足 但短髮的她更有看頭', 'date': '2018-11-25 10:02:00', 'author': '魏家娸', 'contents': '第二女主角林世美在戲中深情愛著蘇志燮的情感也令人為之動容' } ] for layout in layouts: nsoup = NewsSoup(layout['url'], refresh=True, proxy_first=True) self.assertEqual('udn', nsoup.channel) self.assertIn(layout['title'], nsoup.title()) if layout['date'] is not None: self.assertEqual(layout['date'], nsoup.date().strftime(self.dtf)) else: self.assertEqual(layout['date'], None) self.assertEqual(layout['author'], nsoup.author()) self.assertIn(layout['contents'], nsoup.contents())