scrapy爬蟲: https:www.scrapy.org
本篇博客依托的項目: https://github.com/viciousstar/BitcointalkSpider/
一. Scrapy
- 各種依賴庫的安裝請提前參考官方文檔 http://doc.scrapy.org/en/0.24/intro/install.html, 另外python-dev完整的開發庫最好安裝, 可以避免很多不知所以然的問題.
- 如果看英文文檔有困難, 可以先參看一下scrapy中文翻譯項目 http://scrapy-chs.readthedocs.org/zh_CN/latest/
- scrapy.contrib.spiders.Rule中的一些提取規則是以正則表達式形式寫出, 注意網站中的". ?"等符號要進行轉義. eg.
-
Rule(LinkExtractor(allow = ( " https://bitcointalk\.org/index\.php\?board=\d+\.\d+ ", ) ) )
二. scrapy 調試
scrapy本身提供了很好用的交互式調試命令,可以方便調試爬蟲的各種功能。
- 命令格式:scrapy shell url
- 注意事項:
- shell 命令可以需要project,也可以不需要project,當然我們調試的時候如果不是剛剛使用scrapy,肯定是為了調試自己project中的某個功能,這是就需要你在你的project目錄下使用此命令,如果你的url符合當前project的domin,scrapy會自動調用你的spider,此時的交互式python命令行下的全局變量spider就是你自己編寫的spider。
- 因為scrapy shell 命令是在iinux下的命令,如果網址中包括比較特殊的符號,記得進行轉義,比如 “&” 符號。
- 進入python交互命令中,可以用dir(spider),查看spider中的各種屬性,這其中就包括了你自己定義的提取函數,規則等等。
- 注意利用view(response)在瀏覽器中觀察爬蟲看到的網頁是否和我們看到的網頁一樣,其實大部分都是不相同的。
- 未完待續。。。 (有時間會寫一篇詳細的圖文調試過程)
三. 動態網頁爬取的一點,動態url的處理
在爬取 https://bitsharestalk.org 的時候,發現網站會為每一個url增加一個sessionid屬性,可能是為了標記用戶訪問歷史,而且這個seesionid隨着每次訪問都會動態變化,這就為爬蟲的去重處理(即標記已經爬取過的網站)和提取規則增加了難度。
比如https://bitsharestalk.org/index.php?board=5.0 會變成 https://bitsharestalk.org/index.phpPHPSESSID=9771d42640ab3c89eb77e8bd9e220b53&board=5.0,下面介紹集中處理方法
- 僅適用你的爬蟲使用的是scrapy.contrib.spiders.CrawlSpider, 在這個內置爬蟲中,你提取url要通過Rule類來進行提取,其自帶了對提取后的url進行加工的函數。
Rule(LinkExtractor(allow = ( " https://bitsharestalk\.org/index\.php\?PHPSESSID\S*board=\d+\.\d+$ ", " https://bitsharestalk\.org/index\.php\?board=\d+\.\d+$ ")), process_links = ' link_filtering '), #默認函數process_links
Rule(LinkExtractor(allow = ( " https://bitsharestalk\.org/index\.php\?PHPSESSID\S*topic=\d+\.\d+$ ", " https://bitsharestalk\.org/index\.php\?topic=\d+\.\d+$ ", ),),
callback = " extractPost ",
follow = True, process_links = ' link_filtering '),
Rule(LinkExtractor(allow = ( " https://bitsharestalk\.org/index\.php\?PHPSESSID\S*action=profile;u=\d+$ ", " https://bitsharestalk\.org/index\.php\?action=profile;u=\d+$ ", ),),
callback = " extractUser ", process_links = ' link_filtering ')
)
def link_filtering(self, links):
ret = []
for link in links:
url = link.url
# print "This is the yuanlai ", link.url
urlfirst, urllast = url.split( " ? ")
if urllast:
link.url = urlfirst + " ? " + urllast.split( " & ", 1)[1]
# print link.url
return links
link_filtering()函數對url進行了處理,過濾掉了sessid,關於Rule類的process_links函數和links類,官方文檔中並沒有給出介紹,給出一個參考 https://groups.google.com/forum/#!topic/scrapy-users/RHGtm_2GO1M(也許需要梯子,你懂得)
如果你是自己實現的爬蟲,那么url的處理更是可定制的,只需要自己處理一下就可以了。
2. 通用方法,修改scrapy的去重策略,直接用自己的算法替代內置算法。或者編寫自己的scheduler中間件,這一部分筆者沒有親自實現,應該是版本更新,
scrapy這方面有改動,讀者可以自行探索。參考連接: http://blog.pluskid.org/?p=381
四. Xpath--大多是scrapy response 自集成的xpath特性
- 傳送門 http://www.w3.org/TR/xpath20/
- 在使用chrome等瀏覽器自帶的提取extract xpath路徑的時候, 通常現在的瀏覽器都會對html文本進行一定的規范化, 導致明明在瀏覽器中提取正確, 卻在程序中返回錯誤的結果,比如
-
< table cellpadding ="0" cellspacing ="0" border ="0" style ="margin-left: 10px;" >
< tbody >
some others
</ tbody >
</ table>瀏覽器會在table標簽下添加tbody
- 目前本人還沒有什么好的解決方法, 暫時的解決方案是, 多用相對路徑或者是屬性標簽等定位而不依賴於絕對路徑, 如果非要使用絕對路徑的方法:
- scrapy shell somepage
- view(response)
- 然后再開發者工具中看的路徑就是原始路徑
- xpath方法extract()返回的都是unicode字符串, 要注意對其進行的操作, 以及適時轉化為字符串形式(通常情況下函數會自動幫助你轉換, 如果可以轉換的話), 尤其是在一起使用正則表達式的時候會產生命名規則正確卻匹配不到的情況.
- 如果在某個xpath對象下繼續使用xpath規則提取, 當提取某個對象下的所有某個對象所有tr標簽.
-
html = response.xpath( " /html/body ")
tr = html.xpath( " .//tr ") # 搜索body下的所有tr必須加上'.', 否則搜索的是整個文檔的所有tr
五. unicode導入到json文件
使用下載器中間件即可,詳情參考代碼吧。(有時間詳細補充)
ps: 吐槽一下排版,博客排版一直沒找到什么好的工具,只能在網頁版排了,不知道各位能不能推薦一下 -_-||, 拒絕任何形式的轉載。