【Python爬虫实例学习篇】-5、【超详细记录】从爬取微博评论从数据(免登录)到生成词云,新冠病毒问题引起了全国人民的广泛关注。对于这种传染性很强的病毒,人们有不同的声音,我想通过大数据,看看大多数人是怎么想的。亮点:(1)微博评论页的详细链接是一个js脚本(2)获取js脚本链接需要微博的mid参数(3)获取mid参数需要访问微博首页(4)访问微博首页首先需要访问者认证(5)微博首页几乎都是弹窗组成,所有的html代码都隐藏在FM.view()函数的参数中,是json格式工具:Python3.6requests库json库lxml库urllib库jieba库(用于分词)WordCloud库(生成词云)目录:抓取微博评论数据GetWeiBoRemark.py生成词云####1。爬取微博文章数据以央视新闻官方微博置顶第一条微博为例,爬取其评论数据。(1)找到评论页第一步:找到评论页,先用Ctrl+Shift+C选中评论标签,查看它的html代码,发现链接是js脚本,然后尝试用fddler来看看能不能抓到js脚本包,得到这个js的地址。找到疑似js包,解码数据,确认就是我们要找的包。同时,根据“查看更多”,可以确定跳转到的链接,在json解析结果中搜索这个结果,可以进一步确认这个js包就是我们要找的包。接下来需要判断js包是从哪里来的。第二步:找到js包地址。js包地址为:“https://weibo.com/aj/v6/comme...”,链接很长,参数也很多。根据以往的经验,我们尝试删除一些参数进行Access测试。经过测试,发现只有一个参数==mid==就可以拿到数据包。所以有效的js包地址是:“https://weibo.com/aj/v6/comme...”。然后,接下来的工作就是找到mid参数的值(猜测应该是微博唯一序号)。在Fiddler中搜索“mid=4465267293291962”,可以发现在央视新闻首页,每条微博都有该条微博的mid信息。使用Ctrl+Shift+C随机选择一条微博,可以发现有个“mid”属性,里面有mid数据用XPathHelper调试,没有问题,然后在python上实现这部分代码,==(经过下面的测试发现获取评论数据只需要获取微博的mid,所以后面的步骤可以跳过,但是为了保证探索过程的完整性,我还是留在这里作为例子)==获取评论页代码:importrequestsfromlxmlimportetreerequests.packages.urllib3.disable_warnings()name="cctvxinwen"home_url='https://weibo.com/'+nameheaders={"User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/80.0.3970.5Safari/537.36"}session=requests.session()res=session.get(home_url,headers=headers,timeout=20,verify=False)html=etree.HTML(res.content.decode('gb2312',"ignore"))mid_list=html.xpath("//div/@mid")我以为会是轻松获取新闻主页e、但是发现如果没有附加cookie,会自动跳转到微博登录验证页面。使用chrome的无痕访问结合fiddler再次抓包,可以清晰的找到微博验证登录流程。其中最重要的是11号包,剩下的6号包用来提供参数解析,9号包提供==参数s==和参数==sp==的数据,而8号包用于提供9号包访问链接中参数的数据。对于我们的爬虫来说,只需要从8号包开始访问即可。8号包要提交的数据是(常量):cb=gen_callback&fp={"os":"1","browser":"Chrome80,0,3970,5","fonts":"undefined","screenInfo":"1920*1080*24","plugins":"便携式文档格式::internal-pdf-viewer::ChromePDF插件|::mhjfbmdgcfjbbpaeojofohoefgiehjai::ChromePDFViewer|::internal-nacl-plugin::NativeClient"}需要注意的是,在使用requests库时,需要添加:=='Content-Type':'application/x-www-form-urlencoded'==,否则返回数据为空。9号包链接为:“https://passport.weibo.com/vi...”,其中_rand参数可以忽略。这里需要注意的是,在添加tid参数的时候,需要对tid参数进行url编码。9号包接入完成后,即可获取央视新闻微博首页:第三步:获取评论页链接这里有一个很有意思的现象,我在使用xpathhelper调试网页时,可以很容易的获取到对应的属性值,但是一旦用xpath语法应用到python中解析,总是获取到空数据。经过一番调试,发现是微博==“欧盟隐私弹窗”==导致的。我们需要的所有数据都隐藏在这个弹出窗口中。调用FM.view()函数显示微博页面的所有内容。网页的html代码隐藏在FM.view()函数的json格式中。范围。第一部分的代码为:importrequestsimportjsonfromurllibimportparsefromlxmlimportetreerequests.packages.urllib3.disable_warnings()session=requests.session()session.verify=Falsesession.timeout=20name="cctvxinwen"home_url='https://weibo.com/'+nameurl1="https://passport.weibo.com/visitor/genvisitor"urljs='https://weibo.com/aj/v6/comment/small?mid='headers={"用户-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/80.0.3970.5Safari/537.36"}data="cb=gen_callback&fp=%7B%22os%22%3A%221%22%2C%22浏览器%22%3A%22Chrome80%2C0%2C3970%2C5%22%2C%22fonts%22%3A%22undefined%22%2C%22screenInfo%22%3A%221920*1080*24%22%2C%22plugins%22%3A%22Portable%20Document%20Format%3A%3Ainternal-pdf-viewer%3A%3AChrome%20PDF%20Plugin%7C%3A%3Amhjfbmdgcfjbbpaeojofohoefgiehjai%3A%3AChrome%20PDF%20Viewer%7C%3A%3Ainternal-nacl-plugin%3A%3ANative%20Client%22%7D"#获取tidheaders.update({'Content-Type':'application/x-www-form-urlencoded'})tid=json.loads(session.post(url=url1,headers=headers,data=data).content.decode('utf-8')[36:-2])['data']['tid']delheaders['Content-Type']#获取访客cookieurl2="https://passport.weibo.com/visitor/visitor?a=incarnate&t="+parse.quote(tid)+"&w=2&c=095&gc=&cb=cross_domain&from=weibo"session.get(url=url2.encode('utf-8'),headers=headers)#访问微博首页,分析得到评论页res=session.get(url=home_url,headers=headers)html=etree.HTML(res.content.decode('utf-8',"ignore"))#这个json中隐藏了包含mid的html代码mid_json=json.loads(html.xpath("//script")[38].text[8:-1])mid_html=etree.HTML(mid_json['html'])mids=mid_html.xpath("//div/@mid")#get第一条微博的js包地址urljs=urljs+str(mids[0])res=session.get(url=urljs,headers=headers)js_json_html=json.loads(res.content)['data']['html']print(js_json_html)print("当前这条微博的评论数是:"+str(json.loads(res.content)['data']['count']))#解析获取评论页地址js_html=etree.HTML(js_json_html)url_remark=js_html.xpath("//a[@target='_blank']/@href")[-1]url_remark="https:"+url_remark(2)获取并评论获取评论页面后,我们很容易找到评论数据的json包,如图:json包的链接为:"https://weibo.com/aj/v6/comme..."==其中json包的有效链接为:=="https://weibo.com/aj/v6/comme..."得到json包后,就可以提取评论数据了,代码如下==(由于json包不需要其他参数,需要额外提供mid和sum_comment_number参数,所以wearegettingmid那么可以直接跳到这一步)==:(经测试,如果不提供sum_comment_number参数,只能提取前几页的微博评论)爬取评论为如下:2.GetWeiBoRemark.pyimportrequestsimportjsonfromurllibimportparsefromlxmlimportetree#Defaultrequests.packages.urllib3.disable_warnings()session=requests.session()session.verify=Falsesession.timeout=20headers={"User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/80.0.3970.5Safari/537.36"}defgetweiboremark(name,index=1,num=-1):#name参数代表微博首页的名字#index参数代表ents目标微博的序号#num代表要爬取的评论条数,-1代表所有评论#返回结果是评论列表home_url='https://weibo.com/'+nametid=get_tid()get_cookie(tid=tid)mids=get_mids(home_url=home_url)remark_data=get_remarkdata(num=num,mids=mids,index=index)returnremark_datadefget_tid():#获取tidurl1="https://passport.weibo.com/visitor/genvisitor"data="cb=gen_callback&fp=%7B%22os%22%3A%221%22%2C%22browser%22%3A%22Chrome80%2C0%2C3970%2C5%22%2C%22fonts%22%3A%22undefined%22%2C%22screenInfo%22%3A%221920*1080*24%22%2C%22plugins%22%3A%22Portable%20Document%20Format%3A%3Ainternal-pdf-viewer%3A%3AChrome%20PDF%20Plugin%7C%3A%3Amhjfbmdgcfjbbpaeojofohoefgiehjai%3A%3AChrome%20PDF%20Viewer%7C%3A%3Ainternal-nacl-plugin%3A%3ANative%20Client%22%7D"headers.update({'Content-Type':'application/x-www-form-urlencoded'})res=session.post(url=url1,headers=headers,data=data).content.decode('utf-8')[36:-2]tid=json.loads(res)['data']['tid']delheaders['Content-Type']returntiddefget_cookie(tid,session=session):#获取访问cookieurl2="https://passport.weibo.com/visitor/visitor?a=incarnate&t="+parse.quote(tid)+"&w=2&c=095&gc=&cb=cross_domain&from=weibo"session.get(url=url2.encode('utf-8'),标题=headers)defget_mids(home_url,session=session,try_num=0):#访问微博首页,分析获取评论页#获取mids首先要获取cookieres=session.get(url=home_url,headers=headers).content.decode('utf-8',"ignore")html=etree.HTML(res)try:#这个json中隐藏了包含mid的html代码#38为企业微博mid_json=json.loads(html.xpath("//script")[38].text[8:-1])mid_html=etree.HTML(mid_json['html'])mids=mid_html.xpath("//@mid")mids[0]exceptExceptionase:print(e)try:#32是个人微博mid_json=json.loads(html.xpath("//script")[32].text[8:-1])mid_html=etree.HTML(mid_json['html'])mids=mid_html.xpath("//@mid")mids[0]除了Exceptionase:print(e)iftry_num<2:mids=get_mids(home_url,session=session,try_num=try_num+1)iflen(mids)==0:print("多次获取mids失败!程序暂停!")quit()returnnmidsdefget_remarkdata(num,mids,index=1):#获取评论数据url_remarkdata='https://weibo.com/aj/v6/comment/big?ajwvr=6&id={mid}&page={page}&sum_comment_number={comment_number}&from=singleWeiBo'page=1remark_data_new=[]current_num=0whileTrue:print("-"*50)url_remarkdata_new=url_remarkdata.format(mid=str(mids[index]),comment_number=str(current_num),page=str(page))page=page+1print("收集页面评论"+str(page-1)+"!")res=session.get(url=url_remarkdata_new,headers=headers)remark_html=etree.HTML(json.loads(res.content.decode(encoding='utf-8'))['data']['html'])remark_data=remark_html.xpath("//div[@class='list_con']/div[1]/text()")remark_num=json.loads(res.content.decode(encoding='utf-8'))['data']['count']如果页面==2:打印("这条微博共有"+str(remark_num)+'条评论!')ifnum==-1:num=remark_numelifnum>remark_num:num=remark_numforiinremark_data:ifi[0:1]==':':i=i[1:]remark_data_new.append(i.strip())current_num=len(remark_data_new)打印("当前收集:"+str(current_num)+"评论,剩余:"+str(num-current_num)+"待收集!")if(num<=current_num):breakreturnremark_data_newdefsave_remarkdata(name,data):withopen(name,'w',encoding='utf-8')asfp:fp.write(data)fp.flush()fp.close()结果展示:3.生成词云代码如下:fromwordcloudimportWordCloudimportmatplotlib.pyplotaspltimportjiebaimportGetWeiBoRemarkdefproducewordcloud(data,mask=None):word_cloud=WordCloud(background_color="white",font_path='msyh.ttc',mask=mask,max_words=200,max_font_size=100,宽度=1000,height=860).generate(''.join(jieba.cut(data,cut_all=False)))plt.figure()plt.imshow(word_cloud,interpolation='bilinear')plt.axis("off")#不显示坐标轴plt.show()if__name__=='__main__':#cctvxinwenremark_data=GetWeiBoRemark.getweiboremark(name="cctvxinwen",index=2,num=100)str_remark_data=''foriinremark_data:str_remark_data=str_remark_data+str(i)GetWeiBoRemark.save_remarkdata(name='cctvxinwen.txt',data=str_remark_data)producewordcloud(str_remark_data)==目标微博====下面是爬取3000做的词云几条数据:====微信公众号:==