Python爬⾍获取⾖瓣电影短评
Python爬⾍获取⾖瓣电影短评
参考:
该作者提供了基本的思路,但是在运⾏程序过程中发现了⼀些问题并进⾏⼀些修改:
1. 导⼊了re后,却没有写正则表达式,最后也爬取不出结果。因为我是初学者,不清楚其item.findall⼀句是什么意思,因此我重新写了
正则表达式和相关的函数。
2. 如果原作者的这个函数⽣成eachCommentList当中每个元素都是str类型,那么写⼊txt⽂档是ok的,但是如果是列表,则会在写⼊
⽂件时报错。
3. 本⽂只写爬⾍部分,词云部分较简单,可参考笔者其他博客。
全代码展⽰
先展⽰⼀下全部的代码,编译环境:PyCharm。
爬取的⽹站是:
quest
from bs4 import BeautifulSoup
import re
findcomment = repile(r'<span class="short">(.*)</span>')# 根据⽹页的源代码写⼀个正则表达式,对应评论的⽂本
def GetTxt(start):
url ='movie.douban/subject/1849031/comments?start='+ \
str(start)+'&limit=20&sort=new_score&status=P'
head ={# 模拟浏览器头部信息,向服务器发送消息。Firefox浏览器头部信息如下:
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0"
}
request = quest.Request(url, headers=head)
response = quest.urlopen(request)
html_data = ad().decode('utf-8')
commentlist =[]
soup = BeautifulSoup(html_data,'html.parser')
comment_div_lits = soup.find_all('div', class_='comment')
电影源代码人物介绍for item in comment_div_lits:
eachcomment = re.findall(findcomment,str(item))# 如果不把item转换为str类型findall函数会报错
print(eachcomment)# 检查⼀下每⼀条爬取的是否正确
commentlist.append(eachcomment)
f =open('','a', encoding='utf-8')
for comment in commentlist:
if comment !=[]:# 爬取过程发现有些是空列表
f.write(comment[0])
f.close()
def main():
for i in range(1,201,20):# 原本想多爬取⼀些,但是⽹站只允许看到前200条,之后需要登录
print(i)
GetTxt(i)
if __name__ =='__main__':
main()
接下来尽可能详细地逐段讲解.
导⼊库
urllib是访问url,获取数据必须的库。在Python2中似乎是urllib2,但在Python3中,分成了quest和。BeautifulSoup库我也不是很明⽩,但是可以理解成解析⼀个⽹页结构的功能,之后我们可以根据⽹页的源代码提取所需要的部分。(之后系统学了爬⾍我会修正补充关于beautifulsoup这⼀部分)。
re⽤来写正则表达式
quest
from bs4 import BeautifulSoup
import re
正则表达式
因为我只需要影评部分,所以只需要在⽹站源代码到相应的即可,如图:
Firefox浏览器 右键->检查 即可查看源代码。⿏标放在语句上,会相应地在⽹站页⾯标亮其对应的内容,⾮常⽅便。千万不能错,我第⼀次写成了comment-content那个,不是text了。
findcomment = repile(r'<span class="short">(.*)</span>')# 根据⽹页的源代码写⼀个正则表达式,对应评论的⽂本
如果还需要其他结构的正则表达式,就去相应的源代码。有⼀个博客⾮常值得借鉴,我读了之后对⽐着看就知道哪⼀块是什么了:
(确实是零基础⼊门,因为我这⽼年废柴看懂了…)
核⼼——获取url的相关信息
思路:函数的变量是⼀个整数,利⽤⼀个循环,不断访问页⾯(当然是第1页、第2页…第n页),从⽽摘取每⼀页上⾯的评论信息
def GetTxt(start):
url ='movie.douban/subject/1849031/comments?start='+ \
str(start)+'&limit=20&sort=new_score&status=P'
head ={# 模拟浏览器头部信息,向服务器发送消息。Firefox浏览器头部信息如下:
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0"
}
request = quest.Request(url, headers=head)
response = quest.urlopen(request)
html_data = ad().decode('utf-8')
commentlist =[]
soup = BeautifulSoup(html_data,'html.parser')
comment_div_lits = soup.find_all('div', class_='comment')
for item in comment_div_lits:
eachcomment = re.findall(findcomment,str(item))# 如果不把item转换为str类型findall函数会报错
print(eachcomment)# 检查⼀下每⼀条爬取的是否正确
commentlist.append(eachcomment)
f =open('','a', encoding='utf-8')
for comment in commentlist:
if comment !=[]:# 爬取过程发现有些是空列表
f.write(comment[0])
f.close()
拆分开来讲解:
url ='movie.douban/subject/1849031/comments?start='+ \
str(start)+'&limit=20&sort=new_score&status=P'
这就是我们要寻的评论的⽹址,第⼀串字符,是第⼀页的⽹址,随后我们加上循环的正数start,从⽽访问下⼀个页⾯。分析⽹页看到,⼀页有20条,那么很显然start=0之后,下⼀个值是20,在下⼀个40,以此类推。可以⼿动输⼊20,40等,再加上第⼆串字符,看看是否是相应的页⾯。
接下来要伪装⾃⼰,假装⾃⼰是浏览器访问了页⾯,否则会418报错。也就是说写⼀个头部信息:
head ={# 模拟浏览器头部信息,向服务器发送消息。Firefox浏览器头部信息如下:
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0"
}
浏览器头部信息应该是可以随便写,但如果你想查看你的浏览器的,可以。
for item in comment_div_lits:
eachcomment = re.findall(findcomment,str(item))# 如果不把item转换为str类型findall函数会报错
print(eachcomment)# 检查⼀下每⼀条爬取的是否正确
commentlist.append(eachcomment)
对于每⼀个comment_div_lits的项,⼀定要转化为str类型,否则会报错
Traceback (most recent call last):
File "C:\Users\Lenovo\Desktop\1 Project\爬⾍\ceshi.py", line 37,in<module>
main()
File "C:\Users\Lenovo\Desktop\1 Project\爬⾍\ceshi.py", line 33,in main
GetTxt(i)
File "C:\Users\Lenovo\Desktop\1 Project\爬⾍\ceshi.py", line 20,in GetTxt
eachcomment = re.findall(findcomment, item)# 如果不把item转换为str类型findall函数会报错
File "E:\Python\lib\re.py", line 241,in findall
return _compile(pattern, flags).findall(string)
TypeError: expected string or bytes-like object
我们可以打印出每⼀条评论,观察爬取的是否正确。从⽽注意到,⼀些评论没有爬取成功,获得的是⼀个空列表[]。因此在接下来写⼊⽂件的时候,必须要讨论是否是[]的情况,否则index会报错。
f =open('','a', encoding='utf-8')
for comment in commentlist:
if comment !=[]:# 爬取过程发现有些是空列表
f.write(comment[0])
f.close()
主函数调⽤
最后主函数调⽤上⾯的函数即可,如前所述,我们的⽹址应该分别是从0,20,40开始,即设置⼀个变量以20为步长循环。本来想爬4000条数据,但是从跟201开始就不让未登录⽤户看到了。
def main():
for i in range(1,201,20):# 原本想多爬取⼀些,但是⽹站只允许看到前200条,之后需要登录
# print(i)
GetTxt(i)
if __name__ =='__main__':
main()
结果展⽰