Python爬虫获取豆瓣电影短评
参考:使用Python爬虫获取豆瓣影评,并用词云显示
该作者提供了基本的思路,但是在运行程序过程中发现了一些问题并进行一些修改:
- 导入了re后,却没有写正则表达式,最后也爬取不出结果。因为我是初学者,不清楚其item.findall一句是什么意思,因此我重新写了正则表达式和相关的函数。
- 如果原作者的这个函数生成eachCommentList当中每个元素都是str类型,那么写入txt文档是ok的,但是如果是列表,则会在写入文件时报错。
- 本文只写爬虫部分,词云部分较简单,可参考笔者其他博客。
全代码展示
先展示一下全部的代码,编译环境:PyCharm。
爬取的网站是:当幸福来敲门 短评
import urllib.request
from bs4 import BeautifulSoup
import re
findcomment = re.compile(r'<span class="short">(.*)</span>') # 根据网页的源代码写一个正则表达式,对应评论的文本
def GetTxt(start):
url = 'https://movie.douban.com/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 = urllib.request.Request(url, headers=head)
response = urllib.request.urlopen(request)
html_data = response.read().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('content.txt', '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()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
接下来尽可能详细地逐段讲解.
导入库
urllib是访问url,获取数据必须的库。在Python2中似乎是urllib2,但在Python3中,分成了urllib.request和urllib.error。
BeautifulSoup库我也不是很明白,但是可以理解成解析一个网页结构的功能,之后我们可以根据网页的源代码提取所需要的部分。(之后系统学了爬虫我会修正补充关于beautifulsoup这一部分)。
re用来写正则表达式
import urllib.request
from bs4 import BeautifulSoup
import re
- 1
- 2
- 3
正则表达式
因为我只需要影评部分,所以只需要在网站源代码找到相应的即可,如图:
Firefox浏览器 右键->检查 即可查看源代码。鼠标放在语句上,会相应地在网站页面标亮其对应的内容,非常方便。千万不能找错,我第一次写成了comment-content那个,不是text了。
findcomment = re.compile(r'<span class="short">(.*)</span>') # 根据网页的源代码写一个正则表达式,对应评论的文本
- 1
如果还需要其他结构的正则表达式,就去找相应的源代码。有一个博客非常值得借鉴,我读了之后对比着看就知道哪一块是什么了:
Python爬虫超详细讲解(零基础入门,老年人都看的懂)
(确实是零基础入门,因为我这老年废柴看懂了…)
核心——获取url的相关信息
思路:函数的变量是一个整数,利用一个循环,不断访问页面(当然是第1页、第2页…第n页),从而摘取每一页上面的评论信息
def GetTxt(start):
url = 'https://movie.douban.com/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 = urllib.request.Request(url, headers=head)
response = urllib.request.urlopen(request)
html_data = response.read().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('content.txt', 'a', encoding='utf-8')
for comment in commentlist:
if comment != []: # 爬取过程发现有些是空列表
f.write(comment[0])
f.close()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
拆分开来讲解:
url = 'https://movie.douban.com/subject/1849031/comments?start=' + \
str(start) + '&limit=20&sort=new_score&status=P'
- 1
- 2
这就是我们要寻找的评论的网址,第一串字符,是第一页的网址,随后我们加上循环的正数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"
}
- 1
- 2
- 3
浏览器头部信息应该是可以随便写,但如果你想查看你的浏览器的,可以点击此处。
for item in comment_div_lits:
eachcomment = re.findall(findcomment, str(item)) # 如果不把item转换为str类型findall函数会报错
print(eachcomment) # 检查一下每一条爬取的是否正确
commentlist.append(eachcomment)
- 1
- 2
- 3
- 4
对于每一个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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
我们可以打印出每一条评论,观察爬取的是否正确。从而注意到,一些评论没有爬取成功,获得的是一个空列表[]。因此在接下来写入文件的时候,必须要讨论是否是[]的情况,否则index会报错。
f = open('content.txt', 'a', encoding='utf-8')
for comment in commentlist:
if comment != []: # 爬取过程发现有些是空列表
f.write(comment[0])
f.close()
- 1
- 2
- 3
- 4
- 5
主函数调用
最后主函数调用上面的函数即可,如前所述,我们的网址应该分别是从0,20,40开始,即设置一个变量以20为步长循环。本来想爬4000条数据,但是从跟201开始就不让未登录用户看到了。
def main():
for i in range(1, 201, 20): # 原本想多爬取一些,但是网站只允许看到前200条,之后需要登录
# print(i)
GetTxt(i)
if __name__ == '__main__':
main()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
结果展示
补充
上面的代码运行完发现写入txt的全都是一坨,巨难看,所以希望换个行写,把f.write()更改一下。
注意:在print里,只需要print('\n')
就能换行,但是f.write('\n')
只能打印出\n来,要写作f.write('\r\n')
f = open('content.txt', 'a', encoding='utf-8')
for comment in commentlist:
if comment != []: # 爬取过程发现有些是空列表
f.write(comment[0] + '\r\n')
f.close()
- 1
- 2
- 3
- 4
- 5
错漏之处敬请批评指正!