爬取豆瓣的战狼影评(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)

   # 利用urllib2build_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()

 

 

对于上面这些代码 ,部分精解:

爬取豆瓣的战狼影评(cookies 云词)

这是在影评源码中的截图,可以看出我们接下来则需要用正则表达式来进行扣取了。

         先扣取数字,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()

 

接下来,对于以上这些代码精解:

   爬取豆瓣的战狼影评(cookies 云词)

    在此处,可以把comments打印出来,看一下。

   爬取豆瓣的战狼影评(cookies 云词)

这其中有很多字符,也有一些链接。所以接下来需要将这些清除掉。

爬取豆瓣的战狼影评(cookies 云词)

打印看一下,清除掉后的效果。

爬取豆瓣的战狼影评(cookies 云词)

这个在清除的过程中,是有一些暴力排除,所以希望大佬们可以赐教!

接下来,是要将这一些汉字进行分词。

爬取豆瓣的战狼影评(cookies 云词)

将分词结果打印出来看一下。

爬取豆瓣的战狼影评(cookies 云词)

分完词,会发现里面有一些‘的’这一类的无用词,所以和stopwords.txt进行对比,将这些词去掉。然后将词语进行频度统计,最后将云词显示出来。

爬取豆瓣的战狼影评(cookies 云词)

PS:本人还是小白一只,所以会有很多不完善的地方,写下来也是害怕寄几过段时间忘了,所以大佬如果发现有错误,不吝赐教哦~