爬 「某車之家」 網站 實踐

1、寫在前面


一、背景

最近有個爬「某車之家」網站裏論壇帖子的 spike,遇到一系列的問題,遂這裏整理下。css

這裏以爬此網站的「奔騰T99論壇」 爲例。html

二、技術選型

用我最近在搗鼓也最熟悉的框架+庫:scrapy + splashhtml5

三、實現

(1)建表
  • 帖子表 - carPostListpython

  • 帖子的評論表 - carPostgit

    carPost 裏的第一條數據是發帖人的內容github

(2)取捨爬取方法

carPostList 有 api 接口,直接調用獲取 json 數據便可web

carPost 無 api 接口,純服務器端渲染,直接抓取 page source 再用 css selector。mongodb

(3)入庫

這裏選擇存入 mongodb。chrome

  • carPostList - 共 612 條數據docker

  • carPost - 共 10569 條數據

耗時:約 1 hour(設置了每一個請求間隔 3s)

2、遇到的問題


這章是本文的重點,會列舉我遇到的一系列問題,和解決的思路、方法。

一、splash 加載頁面不出來

雖然爬 carPostList 直接調 api 就好,可是我最初是用 splash 來抓的 (參考我以前的 blog: Splash 學習筆記),且遇到個棘手的問題,就是帖子那一塊老是加載不出來,一直顯示 loading,以下圖:

(1)嘗試

一、一開始覺得是網速慢,或者網站自己須要加載更久,因而加大 wait 時間,發現無用。

二、覺得是 request header 的問題,因而加了 User-Agent 、Cookie 等都無用。用 selenuim 作了對比實驗,發現相同的 header 配置 selenuim 卻能夠加載成功,遂排除此條。

注:在用 selenuim 爬的時候,需加上 User-Agent,如 Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.23 Mobile Safari/537.36 ,不然爬取失敗。

三、覺得是 splash 功能配置的問題,因此我把 splash 的幾乎全部有嫌疑的屬性都打開了:

splash.plugins_enabled = true
  splash.indexeddb_enabled = true
  splash.webgl_enabled  = true
  splash.html5_media_enabled = true
  splash.media_source_enabled = true
  splash.request_body_enabled = true
  splash.response_body_enabled = true
  
  # 下面都是默認爲true,我仍是覆寫了一遍。
  splash.js_enabled = true
  splash.images_enabled = true

事實證實仍是無用。

(2)解決辦法

關閉瀏覽器的私有模式 (匿名模式) 便可。(默認是打開的)

作法:splash.private_mode_enabled = false 或者啓動 splash 時指定個參數docker run -p 8050:8050 scrapinghub/splash --disable-private-mode,結果以下圖:

(3)緣由

查閱官方文檔(https://splash-cn-doc.readthedocs.io/zh_CN/latest/faq.html#how-do-i-disable-private-mode)可知:

「有時您仍然須要關閉私有模式,WebKit的本地存儲在開啓私有模式時不能正常工做。而且可能沒法爲本地緩存提供JavaScript填充程序。 所以對於某些站點(某些基於AngularJS站)您須要關閉私有模式。」

看來 splash 的私有模式影響了此網站的 DOM Storage。

官方文檔還說了:

「若是您關閉了私有模式,那麼不一樣請求之間可能會使用一樣的瀏覽器信息(cookie 不受影響)。若是 您下共享環境下使用Splash,您發送請求中的相關信息可能會影響其餘用戶發送的請求。」

因此在通常狀況下,仍是建議打開私有模式。

能夠作一個實驗來證明這一點,即打開 chrome,在 settings -> Cookies and site data -> Block 裏添加此網站,而後再訪問,發現網站確實出現了跟以前同樣加載不出的狀況。

二、帖子內容加密了,須要作字體反爬

在爬取帖子內容時,常常會出現一句話不全的狀況,即少個別字,而這些字在瀏覽器打開則顯示爲粗體樣式,複製粘貼出來則變成了

看來此網站作了反爬措施。

(1)嘗試

我用瀏覽器調試工具,發現這些有兩個特色:

一、這些雖然看上去同樣,可是是不同的。用上面」是「這個粗體字來當例子,複製它,粘貼到 站長工具 - unicode 編碼轉化 裏,點 」中文轉 unicode「 ,發現他的 unicode 值爲 \ued19

二、這些都被一個<span>包裹着,且用了 CSS3 的 @font-face,即:

<span style="font-family: myfont;"></span>

因而下載網站的字體文件(.ttf),用在線的 百度字體編輯器 打開,以下:

發現 "是" 這個字確實對應的是"$ED19"

三、雖然上面咱們找到了字體庫裏包含的與實際漢字的對應關係,可是每次打開新的評論頁面或者頁面刷新,這個字體庫都在實時的變化,即 與實際漢字的對應關係也在不停的變化

(2)解決辦法

我嘗試在 github 上搜索有沒有過來人的經驗,真的找到了:https://github.com/StuPeter/AutoHome_spider,利用這個第三方代碼,我:

一、先抓取評論頁的 page source,裏面的都顯示爲形如 &#xed19;

二、調用第三方代碼,替換爲正常漢字

from AutoHomeFont import get_new_font_dict

# 第三方代碼提供的標準.ttf,只管引用就好
standardFontPath = 'standardFont.ttf'
# 你當前評論頁對應的.ttf(由於每次評論頁.ttf都在變,因此需時刻保持最新)
newFontPath = 'car.ttf'
font_dict = get_new_font_dict(standardFontPath, newFontPath)
        
## 替換文字
# responseStr 爲抓取評論頁的 page source
responseStr = "……<span style='font-family: myfont;'></span>……"
for key, value in font_dict.items(): 
     new_key = '&#x'+key[3:].lower()+';' 
     new_value = eval(repr(value).replace('\\\\', '\\'))
     responseStr = responseStr.replace(new_key, new_value)

三、替換完成後,就能夠順利的進行接下來的 css selector 解析、入庫了。

eval(repr(value).replace('\\', '\')) 的做用是,第三方代碼裏對 unicode 的定義多了一個\,如\\u4f4e,因此須要在替換前減去一個\

相關文章
相關標籤/搜索