最近iOS方面沒(méi)有開(kāi)發(fā)任務(wù), 老板給了我兩周的時(shí)間學(xué)習(xí)爬蟲(chóng). 期間踩了無(wú)數(shù)的坑. 終于算是可以在爬蟲(chóng)方面有所小成, 在學(xué)習(xí)階段很感謝各種大神的技術(shù)文章對(duì)我的幫助. 可是如果你是小白的話, 這些技術(shù)文章的閱讀難度會(huì)比較大. 可能會(huì)導(dǎo)致在學(xué)習(xí)階段在環(huán)境配置, IDE選擇, 初始爬蟲(chóng)上浪費(fèi)很多時(shí)間.
所以這系列文章會(huì)在細(xì)節(jié)上特別重視. 我的主旨就是我踩過(guò)的坑, 就不會(huì)讓你們?cè)俨攘??
學(xué)習(xí)目標(biāo)
三天時(shí)間學(xué)會(huì)對(duì)任一網(wǎng)頁(yè)的爬蟲(chóng), 熟練應(yīng)對(duì)反爬蟲(chóng)機(jī)制. 并對(duì)數(shù)據(jù)匹配, 數(shù)據(jù)保存, 數(shù)據(jù)可視化有充分的了解. 熟悉爬蟲(chóng)基本原理, 熟悉爬蟲(chóng)框架的運(yùn)行.我會(huì)在文章中用很多的小項(xiàng)目來(lái)幫助你們.
學(xué)習(xí)大綱
- 熟悉Python基本語(yǔ)法
- 數(shù)據(jù)流行的框架使用:requests/scrapy等等 框架只是工具
- 熟悉IDE的使用 sublime text/ pycharm
- 數(shù)據(jù)匹配:正則匹配與XPath語(yǔ)法在爬蟲(chóng)中的使用
- 數(shù)據(jù)保存: 將爬取數(shù)據(jù)保存到Excel或者保存為json字符串
- 反爬蟲(chóng)機(jī)制: delay函數(shù)隨機(jī)請(qǐng)求頭, 注入cookie, IP代理池
- ...
閑言碎語(yǔ)
- Python2與Python3的選擇:Python2在2020年會(huì)過(guò)期,現(xiàn)在Python3已經(jīng)很穩(wěn)定了.
如果你是Python的新手,我建議你從Python3開(kāi)始學(xué)習(xí).如果你想通過(guò)學(xué)習(xí)Python, 來(lái)找到工作, 我建議你從Python2學(xué)起, 因?yàn)楝F(xiàn)在有很多公司的項(xiàng)目還是Python2.X的版本.
其實(shí)我認(rèn)為學(xué)習(xí)一門(mén)語(yǔ)言對(duì)于版本這種東西真的是無(wú)所謂了, 學(xué)東西就應(yīng)該融會(huì)貫通, 本文的代碼環(huán)境皆為Python3
而且我認(rèn)為p2與p3最大的區(qū)別就是print函數(shù)帶不帶小括號(hào),哈哈 - 知乎上面有一些很好的文章, 推薦大家在學(xué)習(xí)本文前可以看看.
如何入門(mén)爬蟲(chóng)
爬蟲(chóng)入門(mén)文章匯總
利用爬蟲(chóng)技術(shù)能做到哪些很酷很有趣很有用的事情?
1.基本語(yǔ)法
學(xué)習(xí)任何一門(mén)語(yǔ)言, 必須先學(xué)會(huì)它的基本語(yǔ)法, 這里我推薦廖雪峰的Python教程
廖雪峰Python教程
進(jìn)入網(wǎng)站你會(huì)發(fā)現(xiàn)目錄那么長(zhǎng), 該怎么看. 其實(shí)你只需要看這么多即可開(kāi)始爬蟲(chóng), 是不是很開(kāi)心~
2.開(kāi)發(fā)環(huán)境
現(xiàn)在你已經(jīng)學(xué)會(huì)Python的基本語(yǔ)法了, 也已經(jīng)在shell里面練習(xí)了, 工欲善其事, 必先利其器. 有一個(gè)高效順手的開(kāi)發(fā)環(huán)境是很重要的.
2.1 下載python3
mac自帶的Python版本為2.x, 在終端輸入python --version
即可查看當(dāng)前python的版本.
更新至Python3很簡(jiǎn)單, 首先下載Homebrew, 在終端輸入
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
來(lái)安裝Homebrew, 安裝后直接通過(guò)命令brew install python3
即可.現(xiàn)在你可以輸入python3 --version
來(lái)查看你的python3版本.
2.2 下載sublime text
通過(guò)sublime的官方網(wǎng)址進(jìn)行下載,
2.3 使用與配置sublime text
首先在右下角選擇語(yǔ)言環(huán)境Python
接下來(lái)就可以打出第一行代碼
print('hi python')
, 接下來(lái)按住command+B編譯. 你會(huì)發(fā)現(xiàn)console區(qū)報(bào)錯(cuò)如下/usr/local/bin/python3: can't find '__main__' module in ''
, 原因是沒(méi)有保存就直接運(yùn)行了. 所以我們要先command+S進(jìn)行保存, 然后在運(yùn)行就可以了.
在sublime中輸入漢字:
在編譯器中輸入print('心有猛虎')
, 編譯后會(huì)發(fā)現(xiàn)報(bào)錯(cuò)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
原因是Python采用ASCII處理字符流, 當(dāng)字符流不屬于ASCII范圍內(nèi)時(shí)就會(huì)拋出該異常.解決方法是添加一個(gè)適用于Python3+適配中文環(huán)境的build system.
點(diǎn)擊上方菜單欄中的Tools -> Build System -> New Build System, 就會(huì)打開(kāi)一個(gè)untitled.sublime-build文件,
將以下代碼拷貝進(jìn)去
{
"cmd": ["/usr/local/bin/python3", "-u", "$file"],
"file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
"selector": "source.python",
"env": {"LANG": "en_US.UTF-8"}
}
并保存[最后賦予一個(gè)有意思的名字, 例如我的是python-CN], 再次點(diǎn)開(kāi)Build System就能看見(jiàn)剛剛保存的build system了. 選中后再次運(yùn)行剛才的文件, 就可以print出中文了.
如何修改已經(jīng)保存的Build System:
頂部菜單欄點(diǎn)擊Sublime Text -> Preferences -> Browse Packages -> Packages ->User 雙擊打開(kāi)想要修改的Build System即可
在學(xué)兩個(gè)小技術(shù)點(diǎn), 就可以開(kāi)始我們的第一個(gè)爬蟲(chóng)了, 挺住
2.4 正則表達(dá)式RegEx
這里我只講最淺顯的部分, 我之前對(duì)正則表達(dá)式特別陌生, 可是我只學(xué)了兩分鐘就可以用re來(lái)進(jìn)行數(shù)據(jù)匹配了, 我講的知識(shí)足夠支持我們到學(xué)XPath語(yǔ)法之前了.
先簡(jiǎn)單的看一下這篇文章來(lái)了解下正則表達(dá)式, 看一下這篇文章來(lái)了解一下貪婪模式與非貪婪模式.
簡(jiǎn)單的說(shuō)一下貪婪與非貪婪模式, 貪婪模式就是盡可能多的匹配到滿足條件的內(nèi)容, 非貪婪模式模式與之相反. 在爬蟲(chóng)中, 我們一般使用非貪婪模式.
接下來(lái)舉個(gè)例子, 下面是一段HTML, 該如何使用re來(lái)得到里面的段子呢?
<div class="content">
<span>哥們結(jié)婚彩禮拿了十幾萬(wàn)送粱。女方買(mǎi)彩禮花了幾萬(wàn)并淋。剩下的幾萬(wàn)咙轩。老丈人買(mǎi)了十幾條大狗,當(dāng)初哥們特別不解徽惋,現(xiàn)在知道了课梳,只要敢惹媳婦生氣大年。媳婦就回娘家牽回來(lái)幾條,追著哥們滿村跑鞠呈。</span>
</div>
- 首先引用re的模塊,
import re
- 使用re的匹配函數(shù),
re.findall(pattern, string[, flags])
, 此函數(shù)有三個(gè)參數(shù), 第一個(gè)參數(shù)為匹配規(guī)則pattern, 第二個(gè)匹配參數(shù)string為匹配的內(nèi)容, 第三個(gè)函數(shù)可以對(duì)正則匹配規(guī)則有一定影響,一般我們會(huì)使用re.S, 好讓'.'可以匹配換行符. 這個(gè)函數(shù)會(huì)返回一個(gè)list, 包含所有符合規(guī)則的匹配內(nèi)容.
re.L(re.LOCALE)
讓\w融师、\W、\b蚁吝、\B旱爆、\s和\S依賴(lài)當(dāng)前的locale舀射。
re.M(re.MULTILINE)
影響''和'$'的行為,指定了以后怀伦,''會(huì)增加匹配每行的開(kāi)始(也就是換行符后的位置)脆烟;'$'會(huì)增加匹配每行的結(jié)束(也就是換行符前的位置)。
re.S(re.DOTALL)
影響'.'的行為房待,平時(shí)'.'匹配除換行符以外的所有字符邢羔,指定了本標(biāo)志以后,也可以匹配換行符桑孩。
re.U(re.UNICODE)
讓\w拜鹤、\W、\b流椒、\B敏簿、\d、\D宣虾、\s和\S依賴(lài)Unicode庫(kù)惯裕。
- 如何寫(xiě)匹配規(guī)則: 其實(shí)就是三個(gè)符號(hào)
.*?
, 這三個(gè)符號(hào)代表的是以非貪婪模式匹配拋去換行符的所有字符串. 比如我想拿到"零基礎(chǔ)學(xué)習(xí)爬蟲(chóng)"123456
雙引號(hào)中的內(nèi)容, 就可以寫(xiě)"(.*?)".*?
來(lái)匹配到所需內(nèi)容.
上面的pattern中有兩個(gè).*?
, 他們的區(qū)別為一個(gè)帶括號(hào)和一個(gè)不帶括號(hào), 你可以這么理解, 帶括號(hào)包含的就是我們所需的內(nèi)容, 會(huì)通過(guò)re.findall返回到list中, 因?yàn)槲覀冎恍枰p引號(hào)中的內(nèi)容(零基礎(chǔ)學(xué)習(xí)爬蟲(chóng)), 雙引號(hào)后面的數(shù)字(123456)對(duì)我們來(lái)說(shuō)是無(wú)效內(nèi)容, 所以第二個(gè).*?
無(wú)需帶括號(hào).
現(xiàn)在懂得如何獲取例子中的笑話了么? 代碼如下:
import re
HTML = '<div class="content"><span>哥們結(jié)婚彩禮拿了十幾萬(wàn)。女方買(mǎi)彩禮花了幾萬(wàn)绣硝。剩下的幾萬(wàn)蜻势。老丈人買(mǎi)了十幾條大狗,當(dāng)初哥們特別不解域那,現(xiàn)在知道了咙边,只要敢惹媳婦生氣。媳婦就回娘家牽回來(lái)幾條次员,追著哥們滿村跑败许。</span></div>'
pattern = '<div.*?><span>(.*?)</.*?></div>'
# resutl是一個(gè)list
result = re.findall(pattern, HTML, re.S)
print(result[0])
2.5 requests
爬蟲(chóng)可以大致分為三步:爬取源數(shù)據(jù), 過(guò)濾數(shù)據(jù), 保存數(shù)據(jù).
requests就是實(shí)現(xiàn)第一步的神器, requests可以像url發(fā)送請(qǐng)求, 并將相應(yīng)數(shù)據(jù)呈現(xiàn)給你.
requests主頁(yè)
>>>必看:一篇介紹requests的博客, 寫(xiě)的很好
安裝requests######
- 首先安裝pip, 一會(huì)我們安裝框架基本都會(huì)通過(guò)pip. Mac下自帶easy install, 在終端輸入
sudo easy_install pip
?, 輸入你的電腦密碼(在終端中輸入密碼不會(huì)顯示)即可安裝成功. - 使用pip來(lái)安裝requests, 在終端中輸入
sudo pip3 install requests
, 如果為Python2.X版本安裝, 則輸入sudo pip install requests
使用requests######
首先在sublime text中導(dǎo)入import requests
然后嘗試獲取某個(gè)網(wǎng)頁(yè)的源碼, 這里我們使用簡(jiǎn)書(shū)首頁(yè)為例子r = requests.get('http://www.reibang.com')
現(xiàn)在我們有一個(gè)response對(duì)象, 我們可以從這個(gè)對(duì)象中獲取我們所需的所有內(nèi)容.[詳細(xì)語(yǔ)法看上面的那篇博客]
print(r.text)
就可以打印出簡(jiǎn)書(shū)首頁(yè)的HTML源碼. Requests會(huì)自動(dòng)解碼來(lái)自服務(wù)器的內(nèi)容. 大多數(shù)unicode字符集都能被無(wú)縫地解碼.
請(qǐng)求發(fā)出后,Requests會(huì)基于HTTP頭部對(duì)響應(yīng)的編碼作出有根據(jù)的推測(cè). 當(dāng)你訪問(wèn)r.text 之時(shí)淑蔚,Requests會(huì)使用其推測(cè)的文本編碼. 你可以找出Requests使用了什么編碼市殷,并且能夠使用 r.encoding 屬性來(lái)改變它:
>>> r.encoding
'utf-8'
>>> r.encoding = 'ISO-8859-1'
如果你改變了編碼,每當(dāng)你訪問(wèn) r.text 刹衫,Request都將會(huì)使用 r.encoding 的新值.
所以我們獲取網(wǎng)頁(yè)的源碼很簡(jiǎn)單, 就是一行代碼
r = requests.get(URL)
接下來(lái)就開(kāi)始我們的第一個(gè)項(xiàng)目了
3.項(xiàng)目實(shí)戰(zhàn)
我們項(xiàng)目實(shí)戰(zhàn)為爬取糗事百科熱門(mén)段子中的前10頁(yè), 為什么很多教程都會(huì)選擇糗事百科來(lái)作為爬蟲(chóng)教程呢? 因?yàn)轸苁掳倏茻o(wú)需登錄, 源碼結(jié)構(gòu)性強(qiáng), 學(xué)習(xí)曲線平緩, 很適合作為我們第一個(gè)爬蟲(chóng)練習(xí)項(xiàng)目.
獲取糗事百科網(wǎng)頁(yè)源碼######
導(dǎo)入re與requests模塊, 使用requests發(fā)送get請(qǐng)求獲取網(wǎng)頁(yè)源碼
import requests
import re
def start_spider():
r = requests.get('https://www.qiushibaike.com/8hr/page/1')
print(r.text)
start_spider()
# def是python中定義函數(shù)的.如果這里看不懂def的含義, 請(qǐng)往上翻到1.基本語(yǔ)法那里好好學(xué)習(xí).
這樣我們就可以獲取到糗事百科熱門(mén)第一頁(yè)的源碼了.
根據(jù)網(wǎng)頁(yè)源碼匹配出我們所需的段子######
使用Safari或者Chrome打開(kāi)糗事百科, 按command+option+I打開(kāi)web檢查器, 點(diǎn)擊元素/elements即可查看網(wǎng)頁(yè)源代碼.
爬取這種網(wǎng)頁(yè)時(shí), 相似的數(shù)據(jù)會(huì)有相同的屬性來(lái)包裹. 例如我們想爬取第一頁(yè)的段子, 那么我們先找到所有段子的相同點(diǎn). 鼠標(biāo)懸停在一個(gè)段子上, 右鍵檢查元素.在下方的檢查器中會(huì)發(fā)現(xiàn)所有的段子都被包裹在class='article block untagged mb15'的div標(biāo)簽中了.
展開(kāi)標(biāo)簽, 發(fā)現(xiàn)段子在class="content"的標(biāo)簽中.
我們現(xiàn)在就可以使用正則來(lái)匹配本頁(yè)所有的段子了
import requests
import re
def start_spider():
# 獲取糗事百科源代碼
r = requests.get('https://www.qiushibaike.com/8hr/page/1')
# 使用正則獲取熱門(mén)中的所有段子
pattern = '<div.*?class="article block untagged mb15".*?>.*?<.*?class="content">.*?<span>(.*?)</span>.*?</div>'
duanzi_list = re.findall(pattern, r.text, re.S)
print(duanzi_list)
start_spider()
現(xiàn)在段子黏連的太緊而且還有一些
標(biāo)簽和", 需要對(duì)段子進(jìn)行過(guò)濾.
# 對(duì)段子進(jìn)行過(guò)濾
num = 1
for duanzi in duanzi_list:
filter_duanzi = re.sub('<br/>|"', '', duanzi)
print(str(num) + '.' + filter_duanzi + '\n')
num += 1
這樣是不是就看著好多了?
對(duì)獲取到的段子進(jìn)行保存######
對(duì)段子的保存暫時(shí)用不到數(shù)據(jù)庫(kù)或者Excel, 只需要將段子保存為一個(gè)txt文件即可, 我現(xiàn)在介紹一下在Python中對(duì)文件操作的open函數(shù).
open(name[,mode[,buffering]])
name表示文件名, mode表示讀寫(xiě)模式, buffering是一個(gè)可選參數(shù).
讀寫(xiě)模式:r只讀, r+讀寫(xiě), w新建(會(huì)覆蓋原有文件), a追加.
# 對(duì)段子進(jìn)行過(guò)濾
num = 1
for duanzi in duanzi_list:
filter_duanzi = re.sub('<br/>|"', '', duanzi)
print(str(num) + '.' + filter_duanzi + '\n')
# 保存數(shù)據(jù)
with open('糗事.txt', 'a', encoding ='utf-8') as f:
f.write(str(num) + '.' + filter_duanzi + '\n\n\n')
num += 1
只需要添加兩行代碼, 即可將數(shù)據(jù)保存到txt文件中. txt文件會(huì)保存在與代碼同級(jí)的根目錄中, 打開(kāi)看一看你的成果把~
這樣子你的第一個(gè)爬蟲(chóng)就已經(jīng)成功了, 雖然還有很多不足的地方, 例如只能爬取第一頁(yè), 沒(méi)有交互等等. 這些優(yōu)化我都會(huì)在下個(gè)文章中交給大家的~ 下課!
所有代碼:
import requests
import re
def start_spider():
# 獲取糗事百科源代碼
r = requests.get('https://www.qiushibaike.com/8hr/page/1')
# 使用正則獲取熱門(mén)中的所有段子
pattern = '<div.*?class="article block untagged mb15".*?>.*?<.*?class="content">.*?<span>(.*?)</span>.*?</div>'
duanzi_list = re.findall(pattern, r.text, re.S)
# 對(duì)段子進(jìn)行過(guò)濾
num = 1
for duanzi in duanzi_list:
filter_duanzi = re.sub('<br/>|"', '', duanzi)
print(str(num) + '.' + filter_duanzi + '\n')
# 保存數(shù)據(jù)
with open('糗事.txt', 'a', encoding ='utf-8') as f:
f.write(str(num) + '.' + filter_duanzi + '\n\n\n')
num += 1
start_spider()
預(yù)告
在豬肚篇我會(huì)教給大家:
- 使用面向?qū)ο竽J綍?shū)寫(xiě)爬蟲(chóng)
- 使用XPath語(yǔ)法進(jìn)行數(shù)據(jù)過(guò)濾
- 對(duì)網(wǎng)站反爬蟲(chóng)的一些應(yīng)對(duì)方法
- cookie的使用
- scrapy神器的使用
- 如何將數(shù)據(jù)保存到excel中
- 新IDE-pycharm的使用
- ...
如果大家在爬取數(shù)據(jù)中有任何不懂的地方, 歡迎給我留言, 我會(huì)盡力解決的. 因?yàn)槲疑钪谛率蛛A段碰見(jiàn)問(wèn)題的迷茫感, 我會(huì)陪各位一起度過(guò)的.