[ 自嗨笔记#1] 微博疫情舆情分析—爬取部分
作为一个疫情时入坑的"小学生”,刚刚注册了csdn,这里想和大家交流下学习心得(自己解决代码错误的太难了!),一方面:想看看大家有没有遇到过相关问题,更好的解决方法,另一方面:想把自己的曾经出现过的问题以及解决方式,上传的网上“方便自己随时查看”。虽然大学学过C++,嗯!大学学过(懂的!毕业这么旧已还回!)
疫情期间在家闲来,开始学习Python基础,爬虫,数据分析,这是我开始的给自己的一个学习路线。借助这个疫情主题,给自己做一个小项目,也算个给自己的总结汇报!
正文
三个部分:爬取——数据分析——图标总结报告
爬去部分,主要记录分析过程,代码部分一带而过,自己认为代码部分主要是“术”,爬取思路才是“道”,术忘了可以查的,道是要内化,举一反三的,所以作为了重点
一、下面看下网站情况
URL这里是:/;选择‘战疫情’版块
点进去点每个博文进去,都会有个新的url,且每发现每个url的后面的数字都不同,其他前部相同。这里猜测每串数字都是代表着一个新闻
下拉页面,可以看到“转发数、评论数、点赞数”信息,以及需要抓取的评论内容
网页情况基本是这样!
二、爬取思路
由于我需要的信息(微博正文、博主、发布时间、转发数、评论数、点赞数、评论内容)基本都包括在这个页面中,URL:
“/detail/”+“4504230066683486”的结构,也就是获得每个博文的id就可以访问到,然后抓取。
1.简单思路
三、页面抓取分析
通过”F12“一番寻找,有一点点小线索
点开一个标签后,看到了“一串数字”,似曾相识!就是我们要的id,是json格式
我们下拉主页会发现,出现了“page==2”,第二页出现,这样基本知道每页存在18个新闻,这样可以通过改变页数控制需要的新闻 id 数量。(这里下拉网页可以看到这是动态的信息,下拉到底刷新,看了大佬的文章才知道是Ajax加载的动态链接数据,这种类型不能通过网页的源码直接提取到全部的信息,需要从通道抓包获取。)
微博主页搞定,来看下正文页情况
直接定位,看起来不错找到’div class‘,不过封装在这么多小’a‘标签里面,这样用Xpath筛选出来不太方便呀,CTRL+F查找下看下还有其他地方也存在信息吗?
果然,不仅找到好提取的格式信息,而且还有博主信息(粉丝数,性别等)
正文部分找到了,看下评论信息部分,和前面正文部分一样!经过一番寻找,找到了评论内容以及评论者的信息,也是json格式。
但是这里有很大的不同!
这里可以看到,下拉页可以看到刷新出新URL也不是"page==2"的格式,是"max_id="+“一串数字”,这里比较麻烦,需要再找max_id的线索
观察到上一页的json信息中有max_id的数字刚好和下一页的URL中的max_id段的信息相同,这样就可以,技术路线:单页提取,将json的max_id提取出来,放入到下页URL中,每页包括20个评论,“比如共有89个评论,89 / 20 = 5,也就是5页,可以通过 for 循环5次,实现全部抓取”
最后看下,评论的位置以及看下可用的其他信息
这里json文件类似Python的字典类型,提去信息很方便
四、代码部分
框架思路
完整代码
# -*- coding: utf-8 -*-"""Created on Tue May 19 09:55:29 @author: Administrator"""import requestsimport jsonimport reimport timeimport randomstart_time=time.time()headers={'Cookie' : "_T_WM=72790643300; XSRF-TOKEN=ecaa96; WEIBOCN_FROM=1110006030; SUB=_2A25zx0yBDeRhGeFK71MR-S_OwjSIHXVRSFTJrDV6PUJbkdAKLVXzkW1NQ0tvKI1I2sVjg4nuE5v5eGU-wmim-w6a; SUHB=0eb9kMLYkT2xjK; SCF=Au9bkHrkzgoVu7Rg1Ga1FA7qoMmbNBkYZty58CvrhWLM3ywsXC_WYZAHiyZLo3d88ZnmJiWo35QC-h5cozFseg8.; SSOLoginState=1589853393; MLOGIN=1; M_WEIBOCN_PARAMS=luicode%3D20000174%26uicode%3D20000174",'User-Agent' : 'Mozilla/5.0(Windows NT 10.0;Win64;x64)AppleWebKit/537.36(KHTML,like Gecko) Chrome/81.0.4044.122 Safari/537.36','X-Requested-With' : 'XMLHttpRequest','Referer' : ''}# 抓取数据并获得数据# 1.获得主页所有的新闻标题(网址)# 新浪战役请的主页#======获取新闻id======def get_news_id():news_id=[]for i in range(1): #这里调节爬的信息多少url1 = '/api/feed/trendtop?containerid=102803_ctg1_600059_-_ctg1_600059&page='+str(i)respond=requests.get(url1,headers=headers)for j in respond.json()["data"]["statuses"]:news_id.append(j['id'])time.sleep(0.5)return news_iddef get_news(newsid):ls = []page = {}count = 1for id in newsid:print('正在爬取第{}个微博信息,共{}个'.format(count,len(newsid)))count += 1url2 = '/detail/'+id html = requests.get(url2,headers=headers).text#微博正文wb = re.findall('.*?"text":(.*?),.*?',html)[0]weibo = re.sub('<S*?>[^>]*>.*?|<.*?>','',wb).replace('"','').replace(',',' ').replace('↵','').replace('\n','') #过滤标签#发布时间,并转化格式ct = re.findall('.*?"created_at":(.*?),.*?',html)[0].split(' ')if 'Mar' in ct:created_at = "{}/{}/{} {}".format(ct[-1].replace('"',''), '03', ct[3], ct[-3])elif 'Feb' in ct:created_at = "{}/{}/{} {}".format(ct[-1].replace('"',''), '02', ct[3], ct[-3])elif 'Jan' in ct:created_at = "{}/{}/{} {}".format(ct[-1].replace('"',''), '01', ct[3], ct[-3])elif 'Apr' in ct:created_at = "{}/{}/{} {}".format(ct[-1].replace('"',''), '04', ct[3], ct[-3])elif 'May' in ct:created_at = "{}/{}/{} {}".format(ct[-1].replace('"',''), '05', ct[3], ct[-3])else:created_at=''#楼主idtitle_user_id = re.findall('.*?"id":(.*?),.*?', html)[1]##楼主昵称title_user_name = re.findall('.*?"screen_name": (.*?),.*?',html)[0]#楼主性别title_user_gender = re.findall('.*?"gender":(.*?),.*?', html)#楼主粉丝数title_user_followscount = re.findall('.*?"followers_count":(.*?),.*?', html)#发过微博数title_user_statusescount = re.findall('.*?"statuses_count":(.*?),.*?', html)#转发数reposts_count = re.findall('.*?"reposts_count":(.*?),.*?', html)#评论数comments_count = re.findall('.*?"comments_count":(.*?),.*?', html)#点赞数attitudes_count = re.findall('.*?"attitudes_count":(.*?),.*?', html)l = [id]+[weibo]+[created_at]+[title_user_id]+[title_user_name]+title_user_gender+title_user_followscount+title_user_statusescount+reposts_count+comments_count+attitudes_countls.append(l)page[id] = int(comments_count[0])//20time.sleep(random.randint(3,7)/10) return ls,page# 2.获取每个新闻下的评论单页的jsondef get_json(url,max_id,max_id_type):params = {'max_id' : max_id,'max_id_type' : max_id_type}respond = requests.get(url,params = params,headers = headers)try:if respond.status_code == 200: return respond.json()except requests.ConnectionError as e:print('error',e.args)pass# 获取评论及评论者信息def get_comment(jsdt):ls2=[]for data in jsdt['data']['data']:# 评论正文t=data['text']t1=re.sub('<S*?>[^>]*>.*?|<.*?>','',t).replace(',',' ').replace('↵','').replace('\n','')# 去除表情# 评论点赞数t2=str(data['like_count'])# 评论昵称t3=data['user']['screen_name']# idt4=str(data['user']['id'])# 性别t5=data['user']['gender']# 时间日期tt=data['created_at'].split(' ')if 'Mar' in tt:t6 = "{}/{}/{} {}".format(tt[-1], '03', tt[2],tt[-3])#格式:年/月/日elif 'Feb' in tt:t6 = "{}/{}/{} {}".format(tt[-1], '02', tt[2],tt[-3])elif 'Jan' in tt:t6 = "{}/{}/{} {}".format(tt[-1], '01', tt[2],tt[-3])elif 'Apr' in tt:t6 = "{}/{}/{} {}".format(tt[-1], '04', tt[2],tt[-3])elif 'May' in tt:t6 = "{}/{}/{} {}".format(tt[-1], '05', tt[3],tt[-3])# 粉丝数t7 = str(data['user']['followers_count'])ls2.append([t1]+[t2]+[t3]+[t4]+[t5]+[t6]+[t7])return ls2# 主函数def main():newsid=get_news_id()print('完成newid获取共',len(newsid))ls,page=get_news(newsid)col='新闻id,正文,发布时间,作者id,昵称,性别,粉丝数,共发过微博数,转发数,评论数,点赞数'f=open('weiboNews.csv','a',encoding='utf-8')f.write(col+'\n')for i in ls:f.write(','.join(i)+'\n')f.close()print('已保存weiboNews.csv')col1='评论正文,评论点赞数,评论昵称,id,性别,时间日期,粉丝数,新闻id'+'\n'ff = open('weiboComment.csv','a',encoding='utf-8')ff.write(col1)for n in newsid:print('正在爬取{}的评论'.format(n))max_id = 0max_id_type = 0try:if page[n] == 0:url = '/comments/hotflow?id='+n+'&mid='+n+'&max_id_type=0'jsdt = get_json(url,max_id,max_id_type)list1 = get_comment(jsdt)for i in list1:ff.write(','.join(i+[n])+'\n')else:for j in range(page[n]):#一个评论页的评论url = '/comments/hotflow?id='+n+'&mid='+n+'&max_id_type=0'jsdt=get_json(url,max_id,max_id_type)max_id = jsdt['data']['max_id']max_id_type=jsdt['data']['max_id_type']list1 = get_comment(jsdt)for i in list1:ff.write(','.join(i+[n])+'\n')print('完成')except:print('暂无评论')passtime.sleep(random.randint(3,7)/10)ff.close()print('全部完毕')main()end_time=time.time()use_time=end_time-start_timeprint('用时%s秒' %use_time)
相关文章
[ 自嗨笔记#2] 微博疫情舆情分析—舆情分析部分
[ 自嗨笔记#3] 后浪 评论分析
[ 自嗨笔记#4] 百度文库付费文章-----网页分析
如果觉得《【自嗨笔记#1】微博疫情舆情分析---信息爬取部分》对你有帮助,请点赞、收藏,并留下你的观点哦!