Python爬蟲(chóng)抓取豆瓣TOP250數(shù)據(jù)從分析到實(shí)踐的全過(guò)程(詳細(xì)圖解)

一、開(kāi)門(mén)見(jiàn)山,探究網(wǎng)頁(yè)結(jié)構(gòu)
在爬取之前我們要確定需要的數(shù)據(jù)究竟是在頁(yè)面源代碼里,還是不在頁(yè)面源代碼里(是不是一次性全加載進(jìn)來(lái)的),如果頁(yè)面源代碼里沒(méi)有想要的數(shù)據(jù),說(shuō)明還有其它請(qǐng)求獲取的數(shù)據(jù)。
讓我們打開(kāi)頁(yè)面:

右鍵查看頁(yè)面源代碼,Ctrl+/頁(yè)面搜索關(guān)鍵詞:肖申克
可以看到這時(shí)候我們需要的數(shù)據(jù)是都在頁(yè)面源代碼里的,驗(yàn)證了我們的想法:該頁(yè)面數(shù)據(jù)是一次性全加載進(jìn)來(lái)的,因此得到以下思路。
二、確定思路
1.拿到頁(yè)面源代碼/響應(yīng)
2.編寫(xiě)正則,提取頁(yè)面數(shù)據(jù)
3.保存數(shù)據(jù)
三、步驟詳解
1.初步爬取

1.1 確定請(qǐng)求方式
接下來(lái)按F12,進(jìn)入開(kāi)發(fā)者工具看看怎么個(gè)事兒,發(fā)現(xiàn)有個(gè)Top250(這個(gè)就是第一頁(yè)的頁(yè)面url鏈接,即響應(yīng)就是頁(yè)面源代碼)

1.2 引入request模塊
發(fā)現(xiàn)這里的請(qǐng)求是Get,因此引入request模塊,導(dǎo)入request.get(頁(yè)面鏈接)
?
import requests url="https://movie.douban.com/top250" resp=requests.get(url) #獲取對(duì)應(yīng)頁(yè)面url的請(qǐng)求響應(yīng) pageSource=resp.text #把頁(yè)面源代碼輸出 print(pageSource) #打印
這時(shí)候運(yùn)行發(fā)現(xiàn)結(jié)果是空的:
?
2.繞過(guò)反爬
2.1 加入請(qǐng)求頭
說(shuō)明缺少一個(gè)反爬的驗(yàn)證,瀏覽器自動(dòng)攔截了,這時(shí)候需要加一個(gè)請(qǐng)求頭
import requests
url="https://movie.douban.com/top250"
headers={
"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0"
}
resp=requests.get(url,headers=headers)
pageSource=resp.text
print(pageSource)這樣就可以了:
?
3.編寫(xiě)正則表達(dá)式與正則匹配
3.1 編寫(xiě)正則表達(dá)式
接下來(lái)就需要進(jìn)行數(shù)據(jù)分離:
引入re模塊,編寫(xiě)正則表達(dá)式:
首先從標(biāo)題開(kāi)始提取,從<div class="item">為開(kāi)頭,目標(biāo)是第二個(gè)框里的文字內(nèi)容,這時(shí)候需要用到惰性匹配:.*?
?
3.2 對(duì)比表格
這里樣例的惰性匹配的結(jié)果是兩個(gè)結(jié)果的額原因是開(kāi)啟了全局模式
特性 .*(貪婪).*?(非貪婪/懶惰)核心原則 匹配盡可能多的字符 匹配盡可能少的字符 別名 貪婪模式 非貪婪模式、懶惰模式、最小匹配模式 回溯行為 先吃到尾,再往回找 吃一個(gè)看一次,滿(mǎn)足就停 示例文本 Hello "World" and "Universe"Hello "World" and "Universe"正則 ".*"".*?"匹配結(jié)果 一個(gè)結(jié)果: "World" and "Universe"兩個(gè)結(jié)果: "World"和"Universe"適用場(chǎng)景 匹配大塊的、從開(kāi)始標(biāo)志到結(jié)束標(biāo)志之間的所有內(nèi)容 匹配多個(gè)、成對(duì)標(biāo)簽/引號(hào)之間的單個(gè)內(nèi)容
沒(méi)有
g標(biāo)志:
引擎在找到第一個(gè)匹配項(xiàng)后就停止。
有
g標(biāo)志:
引擎在找到第一個(gè)匹配項(xiàng)后,會(huì)從上次匹配結(jié)束的位置開(kāi)始,繼續(xù)尋找下一個(gè)匹配項(xiàng)。
但是這里還有一個(gè)坑,那就是.在匹配的時(shí)候是跳過(guò)所有非換行符的內(nèi)容
而re.S可以讓正則表達(dá)式中的.匹配換行符
#編寫(xiě)正則表達(dá)式 re.compile(r'<div class="item">.*?<span class="title">(?P<name>.*?)</span>',re.S)
3.3 進(jìn)行正則匹配
接下來(lái)進(jìn)行正則匹配:
#進(jìn)行正則匹配
result=obj.finditer(pageSource)
for item in result:
print(item.group("name"))
?
然后根據(jù)上面的規(guī)則對(duì)源代碼進(jìn)行匹配:
#編寫(xiě)正則表達(dá)式
obj=re.compile(r'<div class="item">.*?<span class="title">(?P<name>.*?)</span>.*?<div class="bd">'
r'.*?<p>.*?導(dǎo)演: (?P<dao>.*?) '
r'.*?<br>(?P<year>.*?) .*?<span class="rating_num" property="v:average">(?P<score>.*?)</span>'
r'.*?<span>(?P<num>.*?)人評(píng)價(jià)</span>',re.S)
#進(jìn)行正則匹配
result=obj.finditer(pageSource)
for item in result:
name=item.group("name")
dao=item.group("dao")
year = item.group("year").strip() #去掉字符串兩側(cè)的空白
score = item.group("score")
num = item.group("num")
print(name,dao,year,score,num)得到了結(jié)果:

3.4 保存文件
接下來(lái)保存為文件:
f=open("top250.csv",mode="w",encoding='utf-8')導(dǎo)出數(shù)據(jù):
f.write(f"{name}{dao}{year}{score}{num}\n")

爬取一頁(yè)的完整代碼:
# 思路:
#
# 1.拿到頁(yè)面源代碼
#
# 2.編寫(xiě)正則,提取頁(yè)面數(shù)據(jù)
#
# 3.保存數(shù)據(jù)
import requests
import re
f=open("top250.csv",mode="w",encoding='utf-8')
url="https://movie.douban.com/top250"
headers={
"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0"
}
resp=requests.get(url,headers=headers)
resp.encoding="utf-8" #解決亂碼問(wèn)題
pageSource=resp.text
#編寫(xiě)正則表達(dá)式
obj=re.compile(r'<div class="item">.*?<span class="title">(?P<name>.*?)</span>.*?<div class="bd">'
r'.*?<p>.*?導(dǎo)演: (?P<dao>.*?) '
r'.*?<br>(?P<year>.*?) .*?<span class="rating_num" property="v:average">(?P<score>.*?)</span>'
r'.*?<span>(?P<num>.*?)人評(píng)價(jià)</span>',re.S)
#進(jìn)行正則匹配
result=obj.finditer(pageSource)
for item in result:
name=item.group("name")
dao=item.group("dao")
year = item.group("year").strip() #去掉字符串兩側(cè)的空白
score = item.group("score")
num = item.group("num")
f.write(f"{name}{dao}{year}{score}{num}\n")
print(name,dao,year,score,num)
f.close()
resp.close()
print("豆瓣Top250提取完畢")
這時(shí)候思考,現(xiàn)在的代碼只能爬取一頁(yè)的25條信息,如何爬取全部250條?

4.翻頁(yè)爬取
由于發(fā)現(xiàn)每跳轉(zhuǎn)一頁(yè)頁(yè)面url的start都會(huì)增加25,因此得出可以用while循環(huán)來(lái)爬取全部數(shù)據(jù)
start=(頁(yè)數(shù)-1)*25

四、完整代碼與注意點(diǎn)
1.完整代碼
# 思路:
#
# 1.拿到頁(yè)面源代碼
#
# 2.編寫(xiě)正則,提取頁(yè)面數(shù)據(jù)
#
# 3.保存數(shù)據(jù)
import requests
import re
f=open("top250.csv",mode="w",encoding='utf-8')
#start=(頁(yè)數(shù)-1)*25
page=1
while page<=10:
url=f"https://movie.douban.com/top250?start={(page - 1) * 25}&filter="
headers={
"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0"
}
resp=requests.get(url,headers=headers)
resp.encoding="utf-8" #解決亂碼問(wèn)題
pageSource=resp.text
#編寫(xiě)正則表達(dá)式
obj=re.compile(r'<div class="item">.*?<span class="title">(?P<name>.*?)</span>.*?<div class="bd">'
r'.*?<p>.*?導(dǎo)演: (?P<dao>.*?) '
r'.*?<br>(?P<year>.*?) .*?<span class="rating_num" property="v:average">(?P<score>.*?)</span>'
r'.*?<span>(?P<num>.*?)人評(píng)價(jià)</span>',re.S)
#進(jìn)行正則匹配
result=obj.finditer(pageSource)
for item in result:
name=item.group("name")
dao=item.group("dao")
year = item.group("year").strip() #去掉字符串兩側(cè)的空白
score = item.group("score")
num = item.group("num")
f.write(f"{name}{dao}{year}{score}{num}\n")
print(name,dao,year,score,num)
print(f"第{page}頁(yè)爬取完成")
page = page + 1
f.close()
resp.close()
print("豆瓣Top250提取完畢")2.注意點(diǎn)
解釋一下
url=f"https://movie.douban.com/top250?start={(page - 1) * 25}&filter="這里的f必須要加
不加 f 的情況:
url="https://movie.douban.com/top250?start={(page - 1) * 25}&filter="實(shí)際URL變成了:
https://movie.douban.com/top250?start={(page - 1) * 25}&filter=注意:{(page - 1) * 25} 被當(dāng)作普通字符串,而不是要計(jì)算的表達(dá)式。無(wú)論 page 是多少,URL 始終是這個(gè)固定的字符串。
豆瓣服務(wù)器收到這個(gè)請(qǐng)求時(shí),看到 start={(page - 1) * 25},它不知道這是什么,通常會(huì)將其視為 start=0 或者忽略這個(gè)參數(shù),所以每次都返回第一頁(yè)的數(shù)據(jù)。
五、結(jié)果展示

成功爬取250條數(shù)據(jù)~
到此這篇關(guān)于Python爬蟲(chóng)抓取豆瓣TOP250數(shù)據(jù)從分析到實(shí)踐的全過(guò)程(詳細(xì)圖解)的文章就介紹到這了,更多相關(guān)Python爬取豆瓣TOP數(shù)據(jù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python 結(jié)巴分詞實(shí)現(xiàn)關(guān)鍵詞抽取分析
這篇文章主要介紹了Python 結(jié)巴分詞實(shí)現(xiàn)關(guān)鍵詞抽取分析,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
Python語(yǔ)言實(shí)現(xiàn)獲取主機(jī)名根據(jù)端口殺死進(jìn)程
這篇文章主要介紹了Python語(yǔ)言實(shí)現(xiàn)獲取主機(jī)名根據(jù)端口殺死進(jìn)程的相關(guān)資料,需要的朋友可以參考下2016-03-03
使用Python將dtso文件轉(zhuǎn)換成dtbo文件的方法
本文介紹了創(chuàng)建DTSO轉(zhuǎn)DTBO工具的步驟,包括安裝Python、使用Python編寫(xiě)命令行和圖形界面應(yīng)用、使用PyInstaller打包為可執(zhí)行文件,以及測(cè)試和分發(fā)注意事項(xiàng),最后提到工具與Flutter無(wú)直接關(guān)聯(lián),后者是Google開(kāi)發(fā)的UI工具包,需要的朋友可以參考下2026-05-05
Python進(jìn)階之高級(jí)用法詳細(xì)總結(jié)
今天帶各位小伙伴學(xué)習(xí)一下Python高級(jí)語(yǔ)法,主要有Lambda表達(dá)式,map函數(shù),filter函數(shù),reduce函數(shù),三大推導(dǎo)式等,文中有非常詳細(xì)的介紹,需要的朋友可以參考下2021-05-05
Numpy數(shù)組array和矩陣matrix轉(zhuǎn)換方法
這篇文章主要介紹了Numpy數(shù)組array和矩陣matrix轉(zhuǎn)換方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
Python?Serial串口的簡(jiǎn)單數(shù)據(jù)收發(fā)方式
這篇文章主要介紹了Python?Serial串口的簡(jiǎn)單數(shù)據(jù)收發(fā)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
python使用sklearn實(shí)現(xiàn)決策樹(shù)的方法示例
這篇文章主要介紹了python使用sklearn實(shí)現(xiàn)決策樹(shù)的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Python使用numpy模塊創(chuàng)建數(shù)組操作示例
這篇文章主要介紹了Python使用numpy模塊創(chuàng)建數(shù)組操作,結(jié)合實(shí)例形式分析了Python使用numpy模塊實(shí)現(xiàn)數(shù)組的創(chuàng)建、賦值、修改、打印等相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2018-06-06

