Python 是一門有用的語言。然而,由於腳本語言缺乏嚴格的類型評估和一些昂貴的操作,它可能會出錯。 根據我個人的經驗,在分析目標變大並且需要並行性的程序中,我經常被Python中不可重現的錯誤所困擾。 我隨意嘗試了一下Kotlin,發現它相當好用,所以我嘗試移植Python3中實現的Scraper。
(順便說一下,我從來沒有真正接觸過Java)
這是 Kotlin 新手,但 Python 線程和 Kotlin 線程的行為似乎不同。
儘管Kotlin的Thread沒有進行進程拆分,但CPU使用率超過100%,因此看起來是使用多個CPU進行高效的執行緒處理。 (也就是說,用Multiprocess劃分後,似乎不需要在其下運行Thread了)
這是在 Ubuntu 上安裝的方法。
$ curl -s https://get.sdkman.io | bash
$ sdk install kotlin
看來JVM記憶體是記錄在環境變數JAVA_OPT中的,正常使用的話會因為記憶體不足而崩潰,所以還是用現代的方式修復一下吧。 我有這樣的設定。
JAVA_OPTS= " -Xmx3000M -Xms3000M "
我不擅長Java,我想過盡可能避免Java的職業規劃,但我覺得學習工具本身會很困難,主要是Eclipse和IDE,因為有很多。
如果用 IDE 來使用 Kotlin 會很方便,但我認為只要用 CUI 編譯和執行沒有問題,CUI 就可以。
編譯的方法有很多,但我們發現將其編譯成jar檔更有用,包括運行時。
$ kotlinc foo.kt -include-runtime -d foo.jar
現在你可以編譯了。
您可以將多個文件合併到一個 jar 中。 (可以參考bar.kt的函數和foo.kt中的Class)
$ kotlinc foo.kt bar.kt -include-runtime -d foo.jar
可以透過將可以使用Java的Maven等編譯的jar檔加入到類別路徑來使用它。 (假設您使用檔案 alice.jar 和 bob.jar)
這非常有幫助,因為它允許我們重複使用許多 Java 資產。
$ kotlinc foo.kt bar.kt -cp alice.jar:bob.jar -include-runtime foo.jar
例如,當使用外部 jar 檔案執行 kotlin jar 時,命令將如下所示。
$ kotlin -cp alice.jar:bob.jar:foo.jar FooKt
這個名字 FooKt 似乎是用來指定包含 main 函數的 foo.kt 檔案。
當使用 JavaScript 進行非同步資料載入時,如果您只是簡單地檢索它並使用 jsoup 等分析它,您將無法取得內容。工作例如,微軟Bing的圖像搜尋是用Ajax渲染的,無法在JavaScript無法工作的環境中工作。 (這是出於實驗目的,所以實際抓取圖像時,請透過API進行。)
val driver = PhantomJSDriver ()
driver.manage().window().setSize( Dimension ( 4096 , 2160 ))
driver.get( " https://www.bing.com/images/search?q= ${encoded} " )
//すべての画像が描画されるのを待つ
Thread .sleep( 3001 )
val html = driver.getPageSource()
html 變數將包含 JavaScript 執行後渲染的 html。透過將其放入jsoup中,您可以找到各種圖像的src URL,根據您找到的圖像的URL,使用wget命令將其儲存在任意目錄下的資料夾中。
val doc = Jsoup .parse(html.toString(), " UTF-8 " )
println (doc.title())
doc.select( " img " ).filter { x ->
x.attr( " class " ) == " mimg "
}.map { x ->
val data_bm = x.attr( " data-bm " )
val src = x.attr( " src " )
Runtime .getRuntime().exec( " wget ${src} -O imgs/ ${name} / ${data_bm} .png " )
}
PhantomJS 需要從該網站下載並放置在 PATH 中。
似乎有多種寫法,但這是最簡單的實作。
{} 中包含的要抓取的整個邏輯成為一個執行緒實例,您可以啟動或加入該執行緒以並行運行它。
val threads = url_details.keys.map { url ->
val th = Thread {
if (url_details[url] !! == "まだ" ) {
_parser (url).map { next ->
urls.add(next)
}
println ( "終わりに更新 : $url " )
url_details[url] = "終わり"
// save urls
_save_conf ( mapper.writeValueAsString(url_details) )
}
}
th
}
看來有一個叫jackson的序列化模組可以在有限的時間內使用。
看來單獨Java庫不行,需要單獨載入Kotlin的模組。
受限制,我嘗試序列化和反序列化 MutableMap<String, DataClass> 但它不起作用。
MutableMap<String, String> 工作正常,所以我不確定嵌套結構是否不好或它是否不支援資料類別。
序列化範例
val mapper = ObjectMapper ().registerKotlinModule()
val serialzied = mapper.writeValueAsString(url_details)
反序列化範例
val mapper = ObjectMapper ().registerKotlinModule()
val url_details = mapper.readValue< MutableMap < String , String >>(json)
首先,git克隆
$ git clone https://github.com/GINK03/kotlin-phantomjs-selenium-jsoup-parser.git
到目前為止,已經實現了兩種類型的抓取:使用廣度優先搜尋簡單地抓取到 100 的深度,而不評估 JavaScript。
(由於我用它來抓取我自己的網站,因此我沒有設置任何特定限制,但預設為 50 或更多並行訪問,因此請相應調整。)
$ sh run.scraper.sh widthSearch ${yourOwnSite}
使用 Microsoft Bing 在影像搜尋畫面上進行搜尋。這是一個實驗程式碼,目的是看看是否可以在不使用 API 的情況下取得使用 Ajax 繪製的內容,因此我認為不應該大量存取並造成麻煩。
搜尋清單請參考github上的kancolle.txt檔案。
sh run.scraper.sh image ${検索クエリリスト} ${出力ディレクトリ}