Python寫爬蟲——抓取網頁並解析HTML

:0:3
發表於 : 2014-08-19 02:01
從網頁中抓取特定信息,我覺得這是一個普遍性的問題,以後經常會遇到。幸虧那個 project 隻是需要我們系的所有教授的信息,大家人工也就算了。如果需要抓取的信息是海量的,舉個栗子,把淘寶上所有的商品目錄抓下來,那豈不是要吐血而亡?我決定好好把爬蟲研究一下。



之前波波寫過一個 java 程序,利用 HTML Parser 去解析團購網站 meituan.com 然後把每天的團購信息存到數據庫裏。稍微改改再爬爬拉手糯米,做個前端,一個團購導航站就問世了。我把程序跑了一下,全自動搜集,不算太複雜。

但是,我覺得 java 太啰嗦,不夠簡潔。Python 這個腳本語言開發起來速度很快,一個活生生的例子是因有關政策 verycd 開始自我閹割,有網友為了搶救資源,把整個 verycd 站爬了下來,鏡像為SimpleCD.org。看了一下爬蟲 源代碼,其實挺簡單。使用方法:

python sitecopy.py




1. 獲取html頁面
其實,最基本的抓站,兩句話就可以了

import urllib2
content = urllib2.urlopen(


這樣可以得到整個 html 文檔,關鍵的問題是我們可能需要從這個文檔中獲取我們需要的有用信息,而不是整個文檔。這就需要解析充滿了各種標籤的 html。

2. 解析 html
SGMLParser
Python 默認自帶 HTMLParser 以及 SGMLParser 等等解析器,前者實在是太難用了,我就用 SGMLParser 寫了一個示例程序:

import urllib2
from sgmllib import SGMLParser

class ListName(SGMLParser):
def __init__(self):
SGMLParser.__init__(self)
self.is_h4 = ""
self.name = []
def start_h4(self, attrs):
self.is_h4 = 1
def end_h4(self):
self.is_h4 = ""
def handle_data(self, text):
if self.is_h4 == 1:
self.name.append(text)

content = urllib2.urlopen("
listname = ListName()
listname.feed(content)
for item in listname.name:
print item.decode("gbk").encode("utf8")


很簡單,這裡定義了一個叫做 ListName 的類,繼承 SGMLParser 裡面的方法。使用一個變量 is_h4 做標記判定 html 文件中的 h4 標籤,如果遇到 h4 標籤,則將標籤內的內容加入到 List 變量 name 中。解釋一下 start_h4() 和 end_h4() 函數,他們原型是 SGMLParser 中的

start_tagname(self, attrs)
end_tagname(self)

tagname 就是標籤名稱,比如當遇到 <pre>,就會調用 start_pre,遇到 </pre>,就會調用end_pre。attrs 為標籤的參數,以 [(attribute, value), (attribute, value), ...] 的形式傳回。

輸出:

虛擬票務
數碼市場
家電市場
女裝市場
男裝市場
童裝童鞋
女鞋市場
男鞋市場
內衣市場
箱包市場
服飾配件
珠寶飾品
美容市場
母嬰市場
家居市場
日用市場
食品/保健
運動鞋服
運動戶外
汽車用品
玩具市場
文化用品市場
愛好市場
生活服務
如果有亂碼,可能是與網頁編碼不一緻,需要替換最後一句 deconde() 的參數,我在香港淘寶默認用的是繁體編碼。各位可以 copy 上面的代碼自己試試,把淘寶的商品目錄抓下來,就是這麼簡單。稍微改改,就可以抽取二級分類等其他信息。

pyQuery
pyQuery 是 jQuery 在 python 中的實現,能夠以 jQuery 的語法來操作解析 HTML 文檔,十分方便。使用前需要安裝,easy_install pyquery 即可,或者 Ubuntu 下

sudo apt-get install python-pyquery


以下例子:

from pyquery import PyQuery as pyq
doc=pyq(url=r"
cts=doc(".market-cat")

for i in cts:
print "====",pyq(i).find("h4").text() ,"===="
for j in pyq(i).find(".sub"):
print pyq(j).text() ,
print "n"


BeautifulSoup
有個頭痛的問題是,大部分的網頁都沒有完全遵照標準來寫,各種莫名其妙的錯誤令人想要找出那個寫網頁的人痛打一頓。為了解決這個問題,我們可以選擇著名的 BeautifulSoup 來解析 html 文檔,它具有很好的容錯能力。

還是用例子來說明吧。我在工作時遇到一個需求,是要查詢某一個 NS 服務器的所有域名,通過搜索我找到 sitedossier.com 這個網站可以提供域名服務器的信息。那麼就要寫個爬蟲來抓查詢結果了,看上去查詢結果頁面就是一個 ol 列表,並不複雜。

sitedossier-result

有點棘手的是如果結果太多,它會進行分頁。爬蟲需要能夠(1)自動翻頁(2)知道最後一頁。最後一頁有“End of list”字符串,所以可以通過正則表達式搞定。

代碼開源在 Github 上,幾個函數都還算清晰可讀,這裡就不貼了。感覺這段腳本還是有點小用處的,比如你可以查到迄今為止有 304373 個域名在用 DNSPOD 解析,或者你想看看新浪 SAE 上到底有多少個網站,又或者了解下百度有些什麼域名,觀察域名規律搶注近似域名神馬的……

用法:

$ python crawler_ns.py -ns dns.baidu.com
# 保存結果到文件:
$ python crawler_ns.py -ns dns.baidu.com >> result.txt


BeautifulSoup 功能強大,我還在研究學習。有進展會更新本文。


[圖擷取自網路,如有疑問請私訊]

本篇
不想錯過? 請追蹤FB專頁!    


© 2017 FUNPEER All Rights Reserved. 使用條款 | 隱私條款 | 侵權舉報 | 聯絡我們


重要聲明:本網站是以即時上載文章的方式運作,本站對所有文章的真實性、完整性及立場等,不負任何法律責任。而一切文章內容只代表發文者個人意見,並非本網站之立場,用戶不應信賴內容,並應自行判斷內容之真實性。發文者擁有在 FUNPEER 張貼的文章。 由於本站是受到「即時發表」運作方式所規限,故不能完全監察所有即時文章,若讀者發現有留言出現問題,請聯絡我們。本站有權刪除任何留言及拒絕任何人士發文,同時亦有不刪除文章的權利。切勿撰寫粗言穢語、誹謗、渲染色情暴力或人身攻擊的言論,敬請自律。本網站保留一切法律權利。US