豆瓣电影短评总数多少不一,但是在短评区只能显示500条评论。
例如《囧妈》,评论数达到117120条。
(当我打开爬到的评论时,还以为自己代码有问题,检查代码未发现问题。用手机登录豆瓣APP发现,电影短评并不是全部显示的。)
所以并不是代码的问题。虽然500条评论有点少,但在写爬虫过程中还是遇到各种bug,寻找解决办法的时候也学习到了很多。
Show Time:导入模块
import requests
from bs4 import BeautifulSoup
import csv
requests和bs4用来获取、解析网页,csv用来储存数据。
2. 获取页面
def download_pages(url):
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3724.8 Safari/537.36',
'Connection': 'keep-alive',
'cookie':'ll="118193"; bid=2-BKkylYZuE; trc_cookie_storage=taboola%2520global%253Auser-id%3D30398b51-ac04-4354-a17e-16f2af9e020b-tuct5157dfe; __gads=ID=f515bc7d9a7a4fd5:T=1578891400:S=ALNI_Maz4pjSB_NxavWDa1fB5IMFQF1MfA; push_doumail_num=0; __utmv=30149280.15092; _vwo_uuid_v2=D300DC12A399D26584AA232FF9F32FBD9|18b180187a8d01fcd0187f0fc2ea37e9; douban-fav-remind=1; douban-profile-remind=1; __yadk_uid=UCh7sYG2OTrqPGlmWgSOlzoYHK4iG3AM; ct=y; vtd-d="1"; push_noty_num=0; ps=y; ap_v=0,6.0; __utma=30149280.1428623878.1578891289.1580356790.1580385922.20; __utmc=30149280; __utmz=30149280.1580385922.20.5.utmcsr=|utmccn=(referral)|utmcmd=referral|utmcct=/passport/login; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1580386771%2C%22https%3A%2F%%2F%22%5D; _pk_ses.100001.4cf6=*; __utma=223695111.1175745079.1578891388.1580356790.1580386771.16; __utmb=223695111.0.10.1580386771; __utmc=223695111; __utmz=223695111.1580386771.16.9.utmcsr=|utmccn=(referral)|utmcmd=referral|utmcct=/; __utmb=30149280.10.10.1580385922; dbcl2="150923360:Fs2wu4qEzLc"; ck=pGFy; _pk_id.100001.4cf6=995f558cb7f52f20.1578891388.16.1580387779.1580360895.'
,'Referer': '/passport/login'
}
r = requests.get(url, headers=headers).content
return r
设置请求头,获取并返回网页内容。
Attention:
刚开始只设置了user-agent,在运行的时候,发现只能读取11页的评论(11*20=220条评论),读取第12页评论时报错。在浏览器中(未登录的状态下)翻到第11页评论,再次点击‘后页’时,出现需要登录的提示。于是在浏览器中登录,复制cookie,粘贴至请求头中。获取Headers内容
3. 获取需要内容,并翻页
def parse_html(html):
soup = BeautifulSoup(html, features='lxml')
page = soup.find('div', attrs={'class':'mod-bd', 'id':'comments'})
comment_list = []
for i in page.find_all('div', attrs={'class':'comment'}):
info = i.find('span', attrs={'class':'comment-info'})
name = info.find('a').getText()
text = i.find('span', attrs={'class':'short'}).getText()
time = i.find('span', attrs={'class':'comment-time'}).getText()
x = info.find('span')
if x.getText() == '看过':
star = x.find_next_sibling('span')['title']
comment_list.append({'ID': name,
'Time': time,
'star': star,
'comments':text})
navi = page.find('div', attrs={'id':'paginator', 'class':'center'})
next_page = navi.find('a', attrs={'class':'next'})
if next_page:
next_url = URL + next_page['href']
print(next_url)
return comment_list, next_url
else:
return comment_list, None
代码详解:
先观察网页元素,用for循环找到每一用户。
需要的抓取的数据是用户名、评级、评论时间、短评。
用户名、短评、时间都可以用getText()直接获取,但是评级,我用了
x.find_next_sibling('span')['title']
因为在评级那一列除了span,没有别的可以定位的元素,获取所需数据后用append加进comment_list列表。
翻页问题:
观察网页元素,可以看到在
page.find('div', attrs={'id':'paginator', 'class':'center'})
后有三条url(首页、前页、后页),我需要后页,后页中有元素class='next',于是可以定位到指向后页的url。最后一页
当翻到最后一页不能再继续翻页了,page.find('div', attrs={'id':'paginator', 'class':'center'}) 后无元素class='next',所以若可以获取指向后页的url则与主url拼接,并返回next_page的url,否则返回None。
navi = page.find('div', attrs={'id':'paginator', 'class':'center'})
next_page = navi.find('a', attrs={'class':'next'})
if next_page:
next_url = URL + next_page['href']
print(next_url)
return comment_list, next_url
else:
print('this is the last page')
return comment_list, None
4. 储存数据
def main():
url = URL
with open('comments.csv','wt', newline='', encoding='utf_8_sig') as comments:
cw = csv.DictWriter(comments, fieldnames=['ID', 'Time', 'star','comments']) #fieldnames必须与dict里的keys相同
cw.writeheader() #先写header避免header被多次写入。
while url:
html = download_pages(url)
comment_list, url = parse_html(html)
cw.writerows(comment_list)
储存数据比较简单,需要注意和我犯过的错误都注释在代码里了。用了while循环,若在上一步中返回了url,就循环两个函数并继续写入数据,若返回None就结束了。
抓取的部分《囧妈》短评如图所示,500条。(第501行里的star是#######,是因为该用户没有评分。)
整理下来发现还是比较简单的,但是从刚刚开始到最后无报错顺利抓取500条短评还是废了零基础的我一些时间的。
最后总结两点:python官方documentation和标准库的查找使用。有时候报错或是不知道该如何继续下去了,在网上找“轮子”也解决不了,可以去看doc,里面有各种方法,要善用。
细心。有时候频频报错或是抓取的数据有问题,最后发现却是细节导致的。
零基础学习Python,方向是数据分析。有不周到的地方,希望同学们能提出来。
谢谢阅读。