學習了urllib,urlib2以及正規表示式之後就可以做一些簡單的抓取以及處理工作。為了抓取方便,這裡選擇糗事百科的網頁作為抓取物件。
1. 獲取資料:
In [293]: url = "http://www.qiushibaike.com/hot" # 如果不加入使用者代理會報錯 In [294]: headers = {"User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0"} In [295]: request = urllib2.Request(url,headers=headers) In [296]: response = urllib2.urlopen(request) In [297]: content = response.read() In [298]: print content <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <meta http-equiv="X-UA-Compatible" content="chrome=1,IE=edge"> <meta name="renderer" content="webkit"/> <meta name="applicable-device" content="pc"> <title>
2. 抓取段子的文字內容:
我用的firefox瀏覽器,按F12,然後進入檢視器,就可以對生成的頁面程式碼進行檢視,當點選某一項的時候會在網頁中標註這一段程式碼會對應頁面中哪一塊。
段子都在id="content-left"的div之中,而其中的每一個子div都是一條段子。
我們展開其中的一條段子,這裡將每一個段子區域劃分為好幾塊:
其中class為contentHerf的<a>中有段子的內容,而我們要抓取就是這個中文內容。
2.1 獲取段子文字內容
更具html結構我們寫一個簡單的獲取段子文字內容的正規表示式:(?:<div.*?class=\"content\">)\s+.*?<span>(.*)<\/span>\s+.*?</div>
(?:<div.*class=\"content\">): 表示匹配分組中內容,但不記入匹配結果。上述表示式的藍色部分是最終獲取的結果
In [313]: pattern = re.compile(r"(?:<div.*class=\"content\">)\s+.*?<span>(.*)<\/span>\s+.*?</div>") # 查詢所有匹配結果 In [314]: result = re.findall(pattern,content) In [315]: print result[0] 跟老婆正在吵架,老丈人碰巧來我家,三人面面相覷,場面十分尷尬,我正不知道該怎麼說話,我老婆手機突然響了,那貨直接按了擴音,竟然是我岳母打來的,琴子,你爸有沒有去你家?我剛跟他吵了一架,老傢伙沒吵贏,離家出走了!<br/>瑪德,更尷尬了!!
\s+.*?的寫法有點繁瑣,這裡在compile函式中加上r.S標誌,將換行符號也納入符號"."中,變換之後的寫法如下:
pattern = re.compile(r"(?:<div.*?class=\"content\">).*?<span>(.*?)<\/span>.*?</div>",re.S)
在段子文字中有用<br/>表示的換行,需要將其替換為\n。這時候可以用sub函式。
In [319]: for item in result: ...: item = re.sub(re.compile(r"<br/>"),r"\n",item) ...: print item 跟老婆正在吵架,老丈人碰巧來我家,三人面面相覷,場面十分尷尬,我正不知道該怎麼說話,我老婆手機突然響了,那貨直接按了擴音,竟然是我岳母打來的,琴子,你爸有沒有去你家?我剛跟他吵了一架,老傢伙沒吵贏,離家出走了! 瑪德,更尷尬了!!
..................
2.2 單獨獲取獲取使用者名稱:
In [354]: pattern = re.compile(r"(?:qiushi_tag_\d+).*?<h2>(.*?)</h2>",re.S) In [355]: result = re.findall(pattern,content) In [356]: len(result) Out[356]: 20 In [357]: print result[0] 匪徒~入庫君
2.3 同時獲取使用者名稱,段子文字內容,以及點贊數量和評論數量:
In [384]: pattern = re.compile(r"(?:qiushi_tag_\d+).*?<h2>(.*?)</h2>.*?(?:contentHerf).*?<span>(.*?)<\/span>.*?(?:class=\"stats\").*?<i.*?>(\d+) ...: </i>.*?<i.*?>(\d+)</i>",re.S) In [385]: result = re.findall(pattern,content) In [386]: for item in result: ...: print "" ...: print "使用者:",item[0] ...: print "段子內容:\n",item[1] ...: print "點贊數量:",item[2] ...: print "評論數量:",item[3]
執行結果結果:
2.4 獲取帶圖片的段子中的圖片地址
不是每一個段子都會有圖片。圖片的的地址一般包含在class="thumb"的div塊中
In [417]: pattern = re.compile(r"(?:class=\"thumb\").*?<img.*?src=\"(.*?)\"",re.S) In [418]: result = re.findall(pattern,content) In [419]:
# 此次抓取中只有五個有圖片的段子 Out[419]: ['http://pic.qiushibaike.com/system/pictures/11778/117782282/medium/app117782282.jpg', 'http://pic.qiushibaike.com/system/pictures/11778/117783971/medium/app117783971.jpg', 'http://pic.qiushibaike.com/system/pictures/11778/117784294/medium/app117784294.jpg', 'http://pic.qiushibaike.com/system/pictures/11778/117782437/medium/app117782437.jpg', 'http://pic.qiushibaike.com/system/pictures/11778/117783530/medium/app117783530.jpg']
2.5 同時獲取使用者名稱,段子文字內容,以及圖片地址,以及點贊數量和評論數量
由於不是每一個段子都會有圖片,所以在抓取的時候有的則抓,有圖片地址的時候才抓取地址。下邊綠色的部分是抓取圖片地址的主程式碼。
In [470]: pattern = re.compile(r"(?:qiushi_tag_\d+).*?<h2>(.*?)</h2>.*?(?:contentHerf).*?<span>(.*?)<\/span>.*?(?:class=\"thumb\".*?<img.*?src=\ "(.*?)\"(?:.*?))?(?:class=\"stats\").*?<i.*?>(\d+)</i>.*?<i.*?>(\d+)</i>",re.S) In [471]: result = re.findall(pattern,content) In [472]: for item in result: ...: print "" ...: print "使用者:",item[0] ...: print "段子內容:\n",item[1] ...: print "段子中圖片地址:",item[2] ...: print "點贊數量:",item[3] ...: print "評論數量:",item[4]
2.6 比較完全的抓取
下邊的正規表示式子中綠色字樣可以看著是不同欄位的分割符號,特別標註部分就是對應獲取欄位的內容的部分。
In [522]: pattern = re.compile(r"(?:qiushi_tag_(\d+)).*?href=\"/users/(\d+)/\".*?img.*?src=\"(.*?)\".*?<h2>(.*?)</h2>.*?(?:contentHerf).*?<span> ...: (.*?)<\/span>.*?(?:class=\"thumb\".*?img.*?src=\"(.*?)\"(?:.*?))?(?:class=\"stats\").*?<i.*?>(\d+)</i>.*?<i.*?>(\d+)</i>",re.S) In [523]: result = re.findall(pattern,content) In [525]: for item in result: ...: print "" ...: print "段子ID:",item[0] ...: print "使用者ID:",item[1] ...: print "使用者頭像:",item[2] ...: print "使用者名稱:",item[3] ...: print "段子內容:\n",item[4] ...: print "段子中圖片地址:",item[5] ...: print "點贊數量:",item[6] ...: print "評論數量:",item[7]