爬取豆瓣的战狼影评(cookies 云词)
本文介绍爬豆瓣电影的战狼影评,并将影评进行清除(去符号、分词、去重、统计),最终做成词云。
最重要的是,豆瓣是需要登录的,如果不登录,爬到第十页左右,会失败。登录的话,可以爬到6000多个影评,才会需要验证码。
登录是cookies。先要模拟登录,这样可以得到网页返回的信息,然后利用这些信息,去request申请网页,得到网页返回的html信息(包含影评信息等)。得到后,进行正则语言来筛选出自己要的信息,保存在zy.csv中。PS:因为这个模拟登录,最后只登陆一次,因为如频繁登录,会被要求输入验证码,是一件相当麻烦而且目前我还未能解决的问题,所以当第一次模拟登录得到信息后,就可以将模拟登录这里的代码屏蔽掉。
整体代码如下:(python_pachong项目中的huic.py中的代码)
#!/usr/bin/env python
# coding=utf-8
from Tkinter import*
import tkMessageBox
import urllib
import urllib2
import re
import requests
import sys
import csv
import codecs
import cookielib
from pip._vendor.requests.cookies import CookieConflictError
reload(sys)
sys.setdefaultencoding("utf-8")
csvfile=file('zy.csv','wb')
csvfile.write(codecs.BOM_UTF8)
writer=csv.writer(csvfile)
def DoPa(html): #两个参数传进来的是URL和一个编好码的K-V对
#以下这些cookie之类的,就是已经知道了登录返回信息,可以利用这些cookie信息去爬网页,然后正则语言来抠出有用信息。
# 创建MozillaCookieJar实例对象
cookie = cookielib.MozillaCookieJar()
# 从文件中读取cookie内容到变量
cookie.load('cookie.txt', ignore_discard=True, ignore_expires=True)
# 创建请求的request
req = urllib2.Request(html)
# 利用urllib2的build_opener方法创建一个opener
print cookie
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
response = opener.open(req)
# print response.read()
text=response.read()
st=r'<divclass=\"comment\">.*?</div>'
ll=re.findall(st, text, re.S)
x=len(ll)
for i in range(0,x):
number=re.compile('.*?<spanclass=\"votes\">(.*?)</span>')
Num=number.findall(ll[i])
name=re.compile('.*?<a href=.*?class=\"\">(.*?)</a>')
Name=name.findall(ll[i])
see=re.compile('.*?<span>(.*?)</span>')
See=see.findall(ll[i])
start=re.compile('.*?<.*?title="(.*?)"></span>')
Start=start.findall(ll[i])
comment_time=re.compile('.*?<span class=\"comment-time\".*?>(.*?)</span>',re.S)
Comment_time=comment_time.findall(ll[i])
comment=re.compile('.*?<p class=\"\">(.*?)</p>',re.S)
Comment=comment.findall(ll[i])
name_0=''
see_0=''
start_0=''
num_0=''
comment_0=''
comment_time_0=''
#这些if else 均是处理这些抠出来的字段是否为空,因为若为空,会报错说range溢出,有了这些if else就可以完美解决。
if len(Name)==0:
name_0=''
else:
name_0=Name[0]
if len(See)==0:
see_0=''
else:
see_0=See[0]
if len(Start)==0:
start_0=''
else:
start_0=Start[0]
if len(Num)==0:
num_0=''
else:
num_0=Num[0]
if len(Comment)==0:
comment_0=''
else:
comment_0=Comment[0]
if len(Comment_time)==0:
comment_time_0=''
else:
comment_time_0=Comment_time[0]
data={
(name_0,see_0,start_0,num_0,comment_0,comment_time_0)#,
}
writer.writerows(data)
nexturl=re.compile('<a href="(.*?)"data-page=\"\" class=\"next\">.*?></a>')
Nexturl=nexturl.findall(text)
DoPa("https://movie.douban.com/subject/26363254/comments"+Nexturl[0])
def Search():
#以下代码就是模拟登录代码,当把这些先执行完的话,result.read()中已经有了信息。
#filename='cookie.txt'
#cookie=cookielib.MozillaCookieJar(filename)
#opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
#postdata=urllib.urlencode({'source':'movie','login':'登录','form_email':'18****9','form_password':'l****.','remember':'on'}) #包含密码用户名 嘿嘿,登录寄几个的哦~
#url ='https://accounts.douban.com/login' #这是登录网址
#result=opener.open(url,postdata)
#cookie.save(ignore_discard=True,ignore_expires=True)
#当执行完以上这些后,将此屏蔽掉,然后将上面的获取网页信息代码放出来执行。
DoPa('https://movie.douban.com/subject/26363254/comments?start=0&limit=20&sort=new_score&status=P') #这是抓取影评第一页网址
def get():
writer.writerow(['用户名','是否看过','评价值','有用人数','评论内容','评论时间']) #,
Search()
csvfile.close()
tkMessageBox.showinfo('温馨提示','采集完毕,文件已经保存到zy.cvs')
get()
对于上面这些代码 ,部分精解:
这是在影评源码中的截图,可以看出我们接下来则需要用正则表达式来进行扣取了。
先扣取数字,r('.*?<spanclass=\"votes>(.*?)</span>')这个正则表达式可以把数字扣取出来,(.*?)这个里面就是所需要的数字。
再扣取用户名,r('.*?<ahref=.*? class=\"\">(.*?)</a>')。
扣取是否看过,r('.*?<span>(.*?)</span>')
扣取星星数量,但是没有明白这里星星数目是怎么控制的,所以就直接扣取后面的总结:较差、力荐、推荐等。r('.*?<span class=.*? titie="(.*?)"></span>')
扣取时间和评论这两个,得稍微注意一下,因为是跨行了,所以需要一些控制。
扣取时间,r('.*?<spanclass=\"comment-time\".*?>(.*?)</span>',re.S) re.S是控制匹配包括换行在内的字符。
扣取评论内容,r('.*?<pclass=\"\">(.*?)</p>',re.S).
以上这些在huic.py中执行完之后,就会有一个zy.csv的文件出现,里面就存着已经爬出来的这些信息。
因为想要的信息已经爬出来存好了,本着不多次爬取的原则,在接下来的云词任务中,就直接用这个zy.csv既可。所以,重新开一个Test.py,来进行对zy.csv中评论内容进行清洗和操作。
Test.py的整体代码:
#!/usr/bin/env python
# coding=utf-8
import csv
import re
import codecs
import jieba #分词包
import pandas as pd
import numpy #计数包
import matplotlib.pyplot as plt #词云显示的时候用到的包,画框的包
#%matplotlib inline
import matplotlib
matplotlib.rcParams['figure.figsize']= (10.0,5.0) #这是显示词云时的框大小
from wordcloud import WordCloud#词云包
comments='' #comments是用来存从zy.csv中的评论内容的
with open('zy.csv','rb') as f:
reader=[each for each in csv.DictReader(f)]
for row in reader: #在每一行中,抽取‘评论内容’
comments+=row['评论内容'] #这样就可以把每个‘评论内容’都放一起,放进一个变量
#print comments
rt=re.sub(r"<a.*?><.*?></a>","",comments) #先将comments中的一些链接清除掉
comments = comments.replace('【',',').replace('】',',').replace('?',',').replace('?',',').replace('!',',').replace(',',',').replace('。','').replace('“',',').replace('”',',').replace('、',',').replace('(',',').replace(')',',') #这些是清除一些符号(目标是将非汉字以外的所以都清除掉)
rt = re.sub("[A-Za-z0-9<>=\"-/:,_()! ]","",comments) #清除数字、字母等
#print rt
segment=jieba.lcut(rt) #开始将之前处理好的进行分词,即将一大段无间断的汉字,分成 #一个个词语
words_df=pd.DataFrame({'segment':segment})
#print words_df.head()
#for i in range(0,len):
# print segment[i]
stopwords=pd.read_csv("stopwords.txt",index_col=False,quoting=3,sep="\t",names=['stopword'],encoding='utf-8')#quoting=3全不引用 stopwords.txt(停用词)是在网上下载的,将刚分好的词语和这个停用词相对比。
words_df=words_df[~words_df.segment.isin(stopwords.stopword)]
print words_df.head()
#下面这是进行词频统计。
words_stat=words_df.groupby(by=['segment'])['segment'].agg({"计数":numpy.size})
words_stat=words_stat.reset_index().sort_values(by=["计数"],ascending=False)
#print words_df.head()
#下面这些是词云的显示
wordcloud=WordCloud(font_path="simhei.ttf",background_color="white",max_font_size=80)
word_frequence = {x[0]:x[1]for xin words_stat.head(10000).values}
word_frequence_list = []
for key in word_frequence:
temp = (key,word_frequence[key])
word_frequence_list.append(temp)
wordcloud=wordcloud.fit_words(word_frequence_list)
plt.imshow(wordcloud)
plt.show()
接下来,对于以上这些代码精解:
在此处,可以把comments打印出来,看一下。
这其中有很多字符,也有一些链接。所以接下来需要将这些清除掉。
打印看一下,清除掉后的效果。
这个在清除的过程中,是有一些暴力排除,所以希望大佬们可以赐教!
接下来,是要将这一些汉字进行分词。
将分词结果打印出来看一下。
分完词,会发现里面有一些‘的’这一类的无用词,所以和stopwords.txt进行对比,将这些词去掉。然后将词语进行频度统计,最后将云词显示出来。
PS:本人还是小白一只,所以会有很多不完善的地方,写下来也是害怕寄几过段时间忘了,所以大佬如果发现有错误,不吝赐教哦~