声明:这里参考了这篇博客的代码
爬取豆瓣影评时,不能使用最简单粗暴的爬虫策略,因为豆瓣服务器
是有反爬虫机制的。简单的粗暴的方式只能爬取四页就会被禁掉。所以这里必须要使用表头,伪装成使用浏览器进行访问。而且需要使用cookie信息。
刚开始使用urllib包来爬取,后来发现困难重重,尽管加了表头跟cookie,但是最多还是只能爬到几百条评论就被禁掉。不知道是因为
表头信息不够还是加的cookie有问题。总之使用这种方法不能爬取全部的
评论信息。给出代码如下,如有大神知道原因,望不吝赐教
#需要爬取的信息:['user_id','rating','comment_time','comment_vote','comment']
from bs4 import BeautifulSoup
import re
import urllib.request
from urllib.error import URLError
import xlwt
import mysql.connector
import time
import urllib.parse
import http.cookiejar
#添加表头信息
my_headers=["Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0"
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/537.75.14"
]
#发送请求
def askURL(url):
import random
filename = 'cookie.txt'
#randdom_header="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
randdom_header=random.choice(my_headers)
cookie = http.cookiejar.MozillaCookieJar(filename)
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie))
postdata = urllib.parse.urlencode({
'账号':'***',
'密码':'***'
})
postdata=postdata.encode(encoding='UTF8')
LOGIN_URL = 'https://accounts.douban.com/login?source=movie'
#模拟登录,并把cookie保存到变量
request = urllib.request.Request(LOGIN_URL, postdata,randdom_header )
try:
response = opener.open(request)#取得响应
html= response.read().decode()#获取网页内容
print(html)
except URLError as e:
if hasattr(e,"code"):
print (e.code)
if hasattr(e,"reason"):
print (e.reason)
cookie.save(ignore_discard=True, ignore_expires=True)
for item in cookie:
print('Name = ' + item.name)
print('Value = ' + item.value)
get_request = urllib.request.Request(url, headers=headers)
get_response = opener.open(get_request)
return get_response
#获取相关内容
def getData(baseurl_1,baseurl_2):
datalist=[]
for i in range(0,300,26):
url=baseurl_1+str(i)+baseurl_2#更新url
html=askURL(url)
time.sleep(1)
soup = BeautifulSoup(html,'lxml')
#找到每一个影评项
for item in soup.find_all('div',class_='comment-item'):
data=[]
#user_id
user_id=item.find('a',class_="").get('title')
#print (user_id)
data.append(user_id)
#rating
rating=item.find('span',class_="rating")
if rating!=None:
rating=rating.get('title')
else:
rating='无评分'
#print(rating)
data.append(rating)
#comment_time
comment_time=item.find('span',class_="comment-time").text.strip()
#print(comment_time)
data.append(comment_time)
#comment_vote
comment_vote=item.find('span',class_="votes pr5").text
#print(comment_vote)
data.append(comment_vote)#添加推荐等级
#comment
comment=item.find("p")
#回应数可能为0,就找不到
if(comment!= None):
comment=comment.text.strip()
else:
comment=str(0)
#print(comment)
data.append(comment)#添加回应数
datalist.append(data)
return datalist
#保存数据到excel
def saveData(datalist,savepath):
book=xlwt.Workbook(encoding='utf-8',style_compression=0)
sheet=book.add_sheet(u'豆瓣影评',cell_overwrite_ok=True)
col=['user_id','rating','comment_time','comment_vote','comment']
for i in range(0,5):
print(i)
sheet.write(0,i,col[i])#列名
for i in range(0,700):#总共700条影评,暂时只爬到700条
data=datalist[i]
for j in range(0,5):#此处需要注意,当评论中包含表情字符,是无法插入excel中的。同样也无法插入数据库中。这里我的解决方法是用正则表达式匹配评论中的汉字。代码在下一篇文章给出
sheet.write(i+1,j,data[j])#数据
book.save(savepath)#保存
def connDB():#连接数据库函数
conn=mysql.connector.connect(user='root',passwd='123456',database='review',charset='utf8mb4')
cursor=conn.cursor()
return(conn,cursor)
def exitConn(conn,cursor):
cursor.close()
conn.close()
#保存数据到数据库
def SaveMysql(datalist):
conn,cursor=connDB();
cursor.execute('create table movie_review2 \
(title varchar(50) ,\
author varchar(20),\
moviename varchar(20),\
movielink varchar(100),\
star varchar(10),\
response varchar(10),\
reviewlink varchar(50),\
useful varchar(10),\
review varchar(8000))')
for i in range(0,50):
data=datalist[i]
print('insert into movie_review2 values\
(%s,%s,%s,%s,%s,%s,%s,%s,%s)',[data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7],data[8]])
cursor.execute('insert into movie_review2 values\
(%s,%s,%s,%s,%s,%s,%s,%s,%s)',[data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7],data[8]])
conn.commit()
exitConn(conn,cursor)
if __name__=='__main__':
baseurl_1='https://movie.douban.com/subject/6982558/comments?start='
baseurl_2='&limit=20&sort=new_score&status=P'
datalist=getData(baseurl_1,baseurl_2)
savepath='豆瓣最受欢迎影评.xls'
saveData(datalist,savepath)
SaveMysql(datalist)
这个程序目前只能抓取八页的影评数据,没有找到原因在哪?后来一哥们使用requests
包使问题得到了解决,而且程序代码要简单很多,下次把可以抓取全部评论数据的代码贴上来。