每一個可以努力的日子,都是一份厚禮。
Python寫爬蟲——抓取網頁並解析HTML
CUHK 上學期有門課叫做 Semantic Web,課程 project 是要搜集整個系裡面的教授信息,輸入到一個系統里,能夠完成諸如“如果選了A教授的課,因時間衝突,B教授的哪些課不能選”、“和A教授實驗室相鄰的實驗室都是哪些教授的”這一類的查詢。這就是所謂的“語義網”了啊。。。然而最坑爹的是,所有這些信息,老師並沒有給一個文檔或者數據庫,全要靠自己去系主頁上搜集。唯一的想法是寫個爬蟲,令人悲哀的是,所有做這個 project 的同學,都是純人肉手工完成,看得我只想扶牆。。。
從網頁中抓取特定信息,我覺得這是一個普遍性的問題,以後經常會遇到。幸虧那個 project 只是需要我們系的所有教授的信息,大家人工也就算了。如果需要抓取的信息是海量的,舉個栗子,把淘寶上所有的商品目錄抓下來,那豈不是要吐血而亡?我決定好好把爬蟲研究一下。
之前波波寫過一個 java 程序,利用 HTML Parser 去解析團購網站 meituan.com 然後把每天的團購信息存到數據庫里。稍微改改再爬爬拉手糯米,做個前端,一個團購導航站就問世了。我把程序跑了一下,全自動搜集,不算太複雜。
但是,我覺得 java 太啰嗦,不夠簡潔。Python 這個腳本語言開發起來速度很快,一個活生生的例子是因有關政策 verycd 開始自我閹割,有網友為了搶救資源,把整個 verycd 站爬了下來,鏡像為 SimpleCD.org。看了一下爬蟲 源代碼,其實挺簡單。使用方法:
python sitecopy.py http://www.163.com |
看看效果:http://www.lovelucy.info/demo/www.163.com
1. 獲取html頁面
其實,最基本的抓站,兩句話就可以了
import urllib2 content = urllib2.urlopen('http://XXXX').read() |
這樣可以得到整個 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('http://list.taobao.com/browse/cat-0.htm').read() 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'http://list.taobao.com/browse/cat-0.htm') 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 列表,並不複雜。
有點棘手的是如果結果太多,它會進行分頁。爬蟲需要能夠(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 功能強大,我還在研究學習。有進展會更新本文。
這篇文章由lovelucy於2011-06-10 22:33發表在編程。你可以訂閱RSS 2.0 也可以發表評論或引用到你的網站。除特殊說明外文章均為本人原創,並遵從署名-非商業性使用-相同方式共享創作協議,轉載或使用請註明作者和來源,尊重知識分享。 |
批評不自由
則讚美無意義
Google Chrome 69.0.3497.81 Windows NT 大約4年前
Traceback (most recent call last):
File “C:/Users/Administrator/Desktop/爬蟲.py”, line 1, in
import urllib2
ModuleNotFoundError: No module named ‘urllib2’
這什麼意思
Google Chrome 50.0.2661.102 Ubuntu Linux 大約8年前
你好,教一個問題
我想通過Shadowsocks翻牆
代碼為:sslocal -s tky.jp.v0.ss-fast.com -p 873 -k f6YVx3 -b 127.0.0.1 -l 1080
但Shadowsocks密碼15分鐘變換一次
密碼網頁https://www.ss-fast.com/ucenter/#?act=free_plan
用python怎樣抓取密碼並實現15分鐘更新執行上述代碼,“f6YVx3”為密碼15分鐘變換一次
Google Chrome 42.0.2311.135 Mac OS X 10_10_3 大約9年前
😛 非常感謝!找了好久,終於發現有一篇實用的教程了~
Google Chrome 39.0.2171.95 Mac OS X 10_10_1 大約9年前
正好是我需要的嘿嘿 😀
Google Chrome 28.0.1500.71 Ubuntu Linux 大約11年前
很受用。
博客不錯,訂閱了。
Mozilla Firefox 20.0 Windows 7 大約11年前
幫你指出個問題,你沒發現你採集的圖片都是模糊的嗎? 問題出再這個函數”urllib2.urlopen(‘http://XXXX’).read()“ 這個函數採集圖片的時候應該用二進制方式打開文件,然後寫入。 還有一個簡單的方法就是 urllib.urlretrieve(img_url, save_name) 直接保存成文件
Google Chrome 27.0.1453.110 Windows 7 大約11年前
Thanks. 我當時也是初學
Google Chrome 31.0.1650.48 Windows 7 大約10年前
樓主 確實非常用功了, 在提取特定的資源時 python 的 re 庫 也是不錯的選擇,正則很強大
Mozilla Firefox 18.0 Windows 7 大約11年前
有個request模塊, 相當好用! 😛
Google Chrome 24.0.1312.2 Mac OS X Lion 10_7_4 大約11年前
😛
Internet Explorer 8.0 Windows XP 大約12年前
好文~!我等新手需要的就是這種一點點積累起來的經驗分享啊 🙄 🙄
不過我感覺把這個稱為semantic web有點…… 😕
這個查詢系統唯一需要理解和計算的是教授們的課程安排,這些應該都是用特定格式整理好的,雖然也是自然語言,但是幾乎可以當成是個純數學問題了。CUHK沒有計算語言學這個研究方向吧?
看了樓上的討論,同問如何解析js……樓主試過wget一定也分享一下經驗啊。還有,通過瀏覽器的方式解析js應該是很靠譜的。python先用正則或者Parser得到參數,調用webkit,傳入參數,抓取內容,是這樣嗎?
Google Chrome 20.0.1132.57 Windows 7 大約12年前
最近也在折騰類似的玩意兒。
我使用的最蛋疼的C++來做的
我做的是一鍵仿站工具。
提取用的是正則表達式。
自動識別文件編碼,文件轉碼之類的都搞定了。但是有3個問題沒能得到解決
希望能得到指點。
1、對於偽靜態的url。我提取到css路徑為相對路徑。這時候,應該如何還原成絕對路徑。
2、對於源碼裡面的flash提取,遇到了麻煩。因為大部分都是用js輸出的,而不是html標籤。
3、需要解析js從而獲取js輸出的內容,比如圖片、flash、iframe等.
後來,準備用python作為C++的腳本,協同工作。但是VC+py3.3 不知道如何發布到未安裝python的計算機上。
還有個想法就是,調用jquery來提取各種資源。
希望能給點意見,謝謝! 🙄
Google Chrome 23.0.1271.64 Windows 7 大約12年前
你搞得太複雜了
js腳本輸出的內容很難直接獲取,你需要一個javascript執行引擎,比如webkit
試試 http://www.phantomjs.org/
以瀏覽器的方式處理頁面,然後輸出
Google Chrome 20.0.1132.57 Windows 7 大約12年前
webkit和V8都是比較不錯的選擇。但是這樣工作量會增加很多,文件體積也顯得很大。不過,還是值得考慮
Google Chrome 23.0.1271.64 Windows 7 大約12年前
By the way
其實,wget很強大……
Google Chrome 20.0.1132.57 Windows 7 大約12年前
wget能解析js嗎?
下載部分,我確實準備用wget來做的 😈
Google Chrome 23.0.1271.64 Windows XP 大約12年前
向你學習!!! ❓
Google Chrome 22.0.1229.79 Linux 大約12年前
菜鳥開始學python,謝謝你的這篇文章
Google Chrome 22.0.1229.94 Windows 7 大約12年前
我也是python菜鳥,多多交流 ^_^
Google Chrome 15.0.874.121 Linux 大約12年前
😎 確實 用正則是王道啊~~
Google Chrome 19.0.1084.56 Windows 7 大約12年前
你這個用正則表達式寫好一點