2020年3月17日 星期二

StanfordNLP 更名為 Stanza

這是 2020/3/6 所做的變更,首頁提供了 Colab 的執行方式


測試一下,感覺滿順的


如同其說明所言,特點如下:

  1. 無痛安裝(尤其是 Colab 很讚)
  2. 全神經網路化工作流程
  3. 支援 66 個人類語言(相當程度上受益於 UD 計劃)
  4. 仍支援 CoreNLP 後端
我滿看好整合 UD 的雄心壯志,感覺是座巴別塔(誤)


2020年3月4日 星期三

以 scrapy 爬蟲抓 ptt 文章,兼論 Anaconda 下 venv 的使用

從頭刻一個當然可以,但有人已經寫好了,在 https://github.com/afunTW/ptt-web-crawler/tree/master/ptt_web_crawler

ptt-web-crawler 是一個沒有使用 scrapy 的專案,協作者 afunTW 將它 fork 了以後以 scrapy 進行改寫。我猜抓下來還是不能直接用,因此 fork 了以後才 clone。為了不影響原環境,並順便解答一些疑問,我在 anaconda 下先安裝了 scrapy ,然後在 clone 下來的目錄中,執行 python -m venv venv。然後新開一個 cmd 並進入 venv 環境,在同一目錄中執行 pip install -r requirements.txt。然後執行 scrapy crawl ptt-web -a board=Gossiping -a pages=1,2 發生三個問題,依序記錄如下

scrapy 指令無法執行

我修改了 requirements.txt ,在最後加入 scrapy 一行,執行 pip install -r requirements.txt。然後執行 scrapy crawl ptt-web -a board=Gossiping -a pages=1,2 發生第二個問題

ModuleNotFoundError: No module named 'scrapy.conf'

出自此行 from scrapy.conf import settings

試著直接comment掉,結果沒問題。可能是我在上一步沒有指定 scrapy 的版本,結果直上 scrapy 2.0 的關係。diff 如下:

--- a/ptt_web_crawler/ptt_web_crawler/spiders/ptt_web_spider.py
+++ b/ptt_web_crawler/ptt_web_crawler/spiders/ptt_web_spider.py
@@ -8,7 +8,7 @@ from six import u

 import scrapy
 from ptt_web_crawler.items import PttWebCrawlerItem
-from scrapy.conf import settings
+# from scrapy.conf import settings
 from scrapy.exceptions import CloseSpider
 from scrapy.http import FormRequest
 from scrapy.spidermiddlewares.httperror import HttpError

執行 scrapy crawl ptt-web -a board=Gossiping -a pages=1,2 發生第三個問題

ImportError: DLL load failed: 找不到指定的模組。

  File "C:\Anaconda3\envs\python 3.7\lib\sqlite3\dbapi2.py", line 27, in
    from _sqlite3 import *

別的專案也遇到相同問題,迫使我回到 python 3.5 開發。看來直接由 cmd 進入新建的 venv 時無法取用 anaconda 已安裝的 sqlite3(以及 scrapy ,如果已經安裝了的話) ,因此必需在 anaconda 的 python 3.7 內進入 venv ,才能正常工作。至於若在新建的 venv 下重新安裝 scrapy ,也無法正常工作,仍然必需使用 anaconda 的套件才能正常工作。

Results

結果會存在 data\Gossiping\Gossiping_page_1_2.json

光兩頁就快 1M 了,改天再來寫一篇這個 json 檔的後處理


2020年3月3日 星期二

generator, generator, 多少 iterator 假汝之名而行

Design Patterns (1994) 自從寫就以來,對程式語言本身似乎沒什麼影響,因為大家都找到自己的方法去實踐。一個例外是 python 的 yield 指令,它嘗試以原生的機制來做到迭代子 (iterator) 功能,通常配合的是 for / next。

拋開這些術語不談,實務上當我們使用迴圈時,會有個邏輯來告訴我們如何取得下一個元素,以及如何回傳結果(如果需要的話)。最簡單的情況,下個元素是累加 1 ,結果則寫入一個串列,並在迴圈結束時回傳 (return)。當下個元素不是累加 1 這麼單純時,若不先生成整個序列,那麼如何能達成相同的目的呢? 直觀上我們可以先生成所要迭代的元素序列。

然而出於記憶體的考量,類似檔案處理為何要走 streaming ,如果能生成每個元素時都立即進行所要的運算,那麼即使整個序列很大也沒關係。其次,生成下個元素的邏輯可以獨立於對元素的運算而抽象化,成為一個可重用的架構,這是第二個好處。

實作上典型的 yield 迭代因此就會有兩層迴圈,內層產生序列,外層逐一取得序列的元素,進行所要的運算。內層迴圈約定好去寫成一個函數,稱為 generator (定義上就是一個有回傳值的 iterator) ,外層則是第一段提到的 for / next 。內層迴圈一旦產生新元素,就必需有個機制暫停內圈執行、保存狀態、回傳元素,這就是 yield 的功用。外層迴圈以 for 迭代 generator ,隱式呼叫了 next 函數,暫停外圈執行、保存狀態、啟動/繼續內圈執行。內圈被執行後會執行到 yield (或結束迴圈產生例外,外圈依約定結束迭代,太細了處不談)暫停內圈執行、保存狀態並回傳元素。外圈取得元素並繼續執行,直到再回到 for 而隱式呼叫 next ,如此週而復始。

說實在的不用 yield 也能依 design pattern 做到相同的事,但是 yield 的工作條件實在太特殊了,這就是一個見仁見智的語言設計。隱約看得到 goto 的影子,不是嗎XD

下圖取自 python yield 語法與 generator 物件介紹