批量看妹子——你的第一個知乎爬蟲(1)

批量看妹子——你的第一個知乎爬蟲(1)

你看著知乎上一個個的爆照貼,想著怎樣能把這些圖片都保存下來呢。

「啊,老師啊,有沒有什麼可以批量保存小姐姐的功能啊」

少年你聽說過爬蟲么,會寫python么

「emmmm,老師我python裝好了,3.6」

孺子可教,走著

把大象放進冰箱里

「老師我知道,第一步打開冰箱門,第二第把大象放進去,第三步關上冰箱門」,這個冷笑話你已經聽了無數遍了,已經學會搶答了。

保存小姐姐也只需要三步:

1.打開網頁2.找到圖片3.保存

你默默的打開了搜索引擎:「如何用python打開網頁」,然後一堆urllib之類的內容宛如天書,你又默默的關閉了網頁。

「老師,有沒有什麼人類也能懂得方法來打來網頁啊」

Requests: HTTP for Humans

「老師,他們還有中文版文檔誒」

STEP 1

安裝了庫,讀了一會文檔後,你寫出了第一步需要的代碼:

Python 代碼(python3):

import requestsurl="https://www.zhihu.com/question/20399991"r = requests.get(url)text= r.text

你心懷期待的跑了一下:

「老師,我把知乎的伺服器搞掛了,你看500了!」

真的這樣么,剛剛不好好的么?你換了瀏覽器結果發現瀏覽器里還好好的啊。

很明顯,知乎伺服器把你給騙了,而且它還很惡意的把你的連接掛了很久,剛剛那段代碼會很久很久才跑出結果。

「難道說,它發現我是爬蟲了?!」

對的

「怎麼發現的呢?」

瀏覽器在發送請求的時候,通常會帶上一個User-Agent,這個字元串里通常會包含操作系統信息和瀏覽器的一些信息。

所以網站才會知道你用的是Android還是iOS,Windows還是Mac,iPad還是iPhone,Chrome還是IE。

「哦,那我們現在的user-agent是啥呢」

默認的是"python-requests/1.2.0"

你打開了Chrome,找到了開發者工具,在Network一欄里,點開一條網路請求,從Request Headers里找到自己瀏覽器的UA

import requestsheader = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"}url="https://www.zhihu.com/question/20399991"r = requests.get(url,headers=header)text= r.text

這樣看起來就是一個正常的Chrome瀏覽器在訪問頁面了

這下就拿到結果了。

STEP 2

你輕輕的在互動式窗口裡輸入了 print text,結果湧現出來的東西把你嚇了一跳。

「這一坨HTML要怎麼辦啊,哪些是圖片呢?我要去怎麼解析他們啊」

「python how to parse html」 你在搜索欄里打下這行字

你熟練的點開了 Stack Overflow的那個連接,準備複製黏貼,高票回答讓你去用一個Beautiful Soup之類的東西。

你默默的打開了煤氣灶,準備煲湯...

「我只想下載個圖片啊,老師能不能簡單點,你說話的方式簡單點...」

你當然可以用類似Beautiful Soup 之類的庫去解析HTML的頁面結構,但是我們需求沒那麼複雜(等湯煲好天都亮了),我們就簡單的寫個正則來匹配下吧。

一個典型的圖片鏈接地址是這樣的,一個典型的圖片鏈接地址是這樣的,pic1.zhimg.com/v2-dfad0 (貼心的知乎做了全站https),觀察下發現,用https://開頭以.jpg結尾,中間任意字元,同時,為了避免匹配到類似a/c.jpg</img>d/f.jpg 這樣的結果,我們需做最短匹配。

最後拿到就拿到了這樣一個式子https://[^s]*?.jpg

「那只有jpg,還有pngjpeggif呢?」

多匹配幾次嘍...

jpg = re.compile(r"https://[^s]*?.jpg")jpeg = re.compile(r"https://[^s]*?.jpeg")gif = re.compile(r"https://[^s]*?.gif")png = re.compile(r"https://[^s]*?.png")imgs=[]imgs+=jpg.findall(text)imgs+=jpeg.findall(text)imgs+=gif.findall(text)imgs+=png.findall(text)

STEP 3

「下載圖片我會!把圖片鏈接寫到txt文件里,然後用迅雷下載!」

放過迅雷吧,寫一個花不了多久的。

def download(url): req = requests.get(url) if req.status_code == requests.codes.ok: name = url.split("/")[-1] f = open("./"+name,"wb") f.write(req.content) f.close() return True else: return False

「然後是一個for循環,挨個下載,然後還能記錄下哪些連接出錯了」,你已經輕車熟路了。

errors = []for img_url in imgs: if download(img_url): print("download :"+img_url) else: errors.append(img_url)print("ERROR URLS:")print(errors)

讓我們運行一下,有圖片了!

以及一坨錯誤的URL:

STEP 5 檢查

「為什麼有兩份呢,還有些莫名其妙的小圖片。」

你把這些圖快速的擼了一遍,啊不,瀏覽了一遍,發現重複的圖片基本以_r和_b結尾,而_r是原圖,而以_l,_xs,_is,結尾的都是頭像,這些沒啥好看的。

「老師我發現了,錯誤的url除了pic4.zhimg.com/***_{size}.jpg之類以外,還有帶轉義符的,轉義符導致我們的正則匹配出了問題,不是一個合法的url.」

「還有啊,這個圖是不是少了點,這個問題可是有一個有700個回答呢」

***_{size}.jpg和一些轉義符都是因為這些內容本來是要經過JS在瀏覽器渲染的,圖少的原因則是因為,答案的載入是有分頁的,網頁上拉倒後面能看到「更多」的按鈕。

稍稍修改下正則表達式,我們只要原圖。

jpg = re.compile(r"https://[^s]*?_r.jpg")jpeg = re.compile(r"https://[^s]*?_r.jpeg")gif = re.compile(r"https://[^s]*?_r.gif")png = re.compile(r"https://[^s]*?_r.png")

給download函數加一個文件夾的參數,把圖片存在文件夾里,然後封裝一個函數,就可以一次批量下載多個URL了。

urls=["https://www.zhihu.com/question/22212644","https://www.zhihu.com/question/22212644", "https://www.zhihu.com/question/31983868","https://www.zhihu.com/question/20399991"]for url in urls : fetch(url)

「具體要怎麼寫啊老師,誒老師你幹嘛去啊...」

自己寫,爆照貼有新回復了,我看圖去...

Final

import osimport reimport requestsdef download(folder,url): if not os.path.exists(folder): os.makedirs(folder) req = requests.get(url) if req.status_code == requests.codes.ok: name = url.split("/")[-1] f = open("./"+folder+"/"+name,"wb") f.write(req.content) f.close() return True else: return Falseheader = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"}errs=[]def fetch(url): r = requests.get(url,headers=header) text= r.text imgs=[] jpg = re.compile(r"https://[^s]*?_r.jpg") jpeg = re.compile(r"https://[^s]*?_r.jpeg") gif = re.compile(r"https://[^s]*?_r.gif") png = re.compile(r"https://[^s]*?_r.png") imgs+=jpg.findall(text) imgs+=jpeg.findall(text) imgs+=gif.findall(text) imgs+=png.findall(text) errors = [] folder = url.split("/")[-1] for img_url in imgs: if download(folder,img_url): print("download :"+img_url) else: errors.append(img_url) return errorsurls=["https://www.zhihu.com/question/22212644","https://www.zhihu.com/question/29814297", "https://www.zhihu.com/question/31983868","https://www.zhihu.com/question/20399991"]for url in urls : print(url) errs+=fetch(url)print("ERROR URLS:")print(errs)

End

「老師,那我們要怎樣才能獲取到完整的回答啊,以及怎麼把小姐姐們和照片對應起來啊」

那是下次的內容啦

「那老師下次去哪裡找你啊」

關注我就好啦。

更新:批量看妹子——你的第一個知乎爬蟲(2)

推薦閱讀:

在 Pycom 使用 Python + Micropython + MQTT 進行物聯網編程
Python 字元編碼的二三事
乾貨|Scikit-Learn的五種機器學習方法使用案例(python代碼)
文獻引文分析利器 HistCite 詳細使用教程(精簡易用免安裝版本 HistCite Pro 首發頁面)
OnlineJudge 2.0發布

TAG:Python | 网页爬虫 |