前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python实现单博主微博文本、图片及热评爬取

Python实现单博主微博文本、图片及热评爬取

作者头像
慕白
发布2018-07-06 14:54:27
1.3K0
发布2018-07-06 14:54:27
举报
文章被收录于专栏:极客慕白的成长之路

文章简介

经常刷微博的同学肯定会关注一些有比较意思的博主,看看他们发的文字、图片、视频和底下评论,但时间一长,可能因为各种各样的原因,等你想去翻看某个博主的某条微博时,发现它已经被删除了,更夸张的是发现该博主已经被封号。那么如果你有很感兴趣的博主,不妨定期将Ta的微博保存,这样即使明天微博服务器全炸了,你也不用担心找不到那些微博了。(自己的微博也同理哦。)

看网上一些微博爬虫,都是针对很早之前的微博版本,而且爬取内容不全面,比如长微博不能完整爬取、图片没有爬取或没有分类,已经不适用于对当下版本微博内容的完整爬取了。

本例主要基于Python3.6.2版本,能够实现对于单博主微博内容的完整爬取、编号整理和本地保存。

环境介绍

Python3.6.2/Windows-7-64位/微博移动端

实现目标

将微博上你感兴趣的博主微博(全部或过滤非原创等)内容获取,包括微博文本、图片和热评,文本和热评按编号存入txt文件中,图片按编号存入指定路径文件夹中。这样一来方便对你关注的微博信息进行定期保存以及后期的检索查阅,二来将这些数据获取后也可以对博主微博、评论等信息进行进一步的数据分析。

本例中获取数据保存在本地文件系统,如爬取数据量大,可考虑使用MongoDB等数据库,方便数据存储和检索查阅。

准备工作

一般来说同一网站,PC站的信息较为全面,但不易爬取,而移动端则相对来说比较简单,因此本例中选取移动端站点m.weibo.com作为入口来进行爬取。

进入所要爬取的博主的主页,以我关注的“博物杂志”为例,发现其主页url为:https://m.weibo.cn/u/1195054531?uid=1195054531&luicode=10000011&lfid=100103type%3D1%26q%3D%E5%8D%9A%E7%89%A9%E6%9D%82%E5%BF%97 

其中1195054531这段数字就是我们要找的uid,然后打开在浏览器中输入url: m.weibo.cn/u/1195054531 再次进入相同主页,这时候按F12打开谷歌开发者工具,点“Network”,因为移动端站点加载方式为异步加载,我们主要关注XHR下请求,点“XHR”,按F5刷新重新发送请求。这时候发现浏览器已经发送两个请求,第一个请求主要是为了获取一些和博主相关的介绍信息,而第二个请求就是为了获取第一页所有微博的信息,我们重点关注第二个请求。

点“Headers”,可以发现Request URL 、Cookie、Referer等我们需要的信息(Cookie信息这里采用手动获取方式,有效时间为几个小时不等,过期后需要手动重新获取一下), 其中Request URL为 https://m.weibo.cn/api/container/getIndex?type=uid&value=1195054531&containerid=1076031195054531 

后面通过观察发现,在这个url末尾加上&page=页数可以控制想要爬取的微博页数。 点“Preview”:

观察返回的json数据,cards下就是一条条微博的信息card。 点开mblog,可以获取详细的微博相关内容:

我们主要需要以下数据: ‘id’:微博编号 ‘text’:微博文本 ‘islongText’:判断该条微博是否为长微博 ‘bmiddle_pic’:判断该微博是否带有图片

点开某条具体微博,来到微博完整内容和评论页面,同理通过观察“Network中请求相关信息,可以发现该页面url为: https://m.weibo.cn/api/comments/show?id=3900009063730800&page=1 其中id后面数字即为我们前面获取的微博编号,page参数可控制微博页数,请求返回json格式数据如下:

其中’data’和’hotdata’分别为评论和热评数据。

实现逻辑

  1. 通过控制page参数获取每页微博的cards数据,其中包含各条微博的详细信息;
  2. 开始遍历每一页微博页,同时遍历每一页的每一个微博,期间进行如下操作:
  3. 判断是否为长微博,如不是获取文本信息,否则进入详细微博内容请求,获取文本信息,将文本信息写入txt文档;
  4. 判断微博是否带有图片,如有通过请求获取图片地址,遍历地址,将其链接写入txt文档,将图片保存到本地,如无图片结束;
  5. 通过微博评论请求,获取评论数据列表,遍历列表获得该微博下每一条评论并保存到txt文档中相应微博内容下; …… 直到遍历完每一条微博。

爬取过程

爬取结果

文件夹中为对应微博图片,txt文档中为爬取的微博文本、评论内容。

以爬取“博物杂志”第3条微博为例,原博内容如下:

Txt文本中微博文本和评论如下:

文件夹中对应图片如下:

相对来说可以比较方便地进行检索和查阅。   

代码实现

# -*- coding:utf-8 -*- ''' Created on 2018年3月9日 @author: ora_jason ''' from lxmlimport html import requests import json import re import os import time import urllib.request class CrawlWeibo: # 获取指定博主的所有微博cards的list defgetCards(self, id, page): # id(字符串类型):博主的用户id;page(整型):微博翻页参数 ii = 0 list_cards = [] while ii < page: ii = ii + 1 print('正在爬取第%d页cards' % ii) url = 'https://m.weibo.cn/api/container/getIndex?type=uid&value=' + id + '&containerid=107603' + id + '&page=' + str( ii) response = requests.get(url, headers=headers) ob_json = json.loads(response.text) # ob_json为dict类型 list_cards.append(ob_json['data']['cards']) # ob_json['data']['cards']为list类型 time.sleep(2) print('暂停2秒') # 爬完一页所有微博的cards后 停顿两秒 return list_cards# 返回所有页的cards # 获取某条微博的热门评论或评论的list defgetComments(self, id, page): # id(字符串类型):某条微博的id;page(整型):评论翻页参数 url = 'https://m.weibo.cn/api/comments/show?id=' + id + '&page=' + str(page) response = requests.get(url, headers=headers) ob_json = json.loads(response.text) list_comments = [] if 'data' in ob_json: if 'hot_data' in ob_json['data']: list_comments = ob_json['data']['hot_data'] else: list_comments = ob_json['data']['data'] return list_comments# 返回某条微博下评论 defgetAll(self, id, page, path): # id为博主uid,page为爬取页数,path为保存路径 list_cards = self.getCards(id, page) print('爬取页数为:' + str(len(list_cards)) + '\n' + 30 * '-') count_weibo = 1 page_weibo = 1 # 遍历当页所有微博,保存内容,并根据id查找输出热门评论 for cards in list_cards: for card in cards: if card['card_type'] == 9: # 过滤出微博 #if card['card_type'] == 9 and 'raw_text' not in card['mblog']: # 过滤出原创微博 print('正在爬取第' + str(page_weibo) + '页 第' + str(count_weibo) + '条card') mid = card['mblog']['id'] created_at = card['mblog']['created_at'] # 获取保存文本信息 if card['mblog']['isLongText'] == 'false': text = card['mblog']['text'] else: url = 'https://m.weibo.cn/statuses/extend?id=' + mid response = requests.get(url, headers=headers) ob_json = json.loads(response.text) # ob_json为dict类型 text = ob_json['data']['longTextContent'] tree = html.fromstring(text) text = tree.xpath('string(.)') # 用string函数过滤掉多余标签 # 输出微博文本 with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff: ff.write('第' + str(count_weibo) + '条\n' + '*** 发布于 ' + created_at + ' ***' + '\n') ff.write(text + '\n') # 获取保存图片 if 'bmiddle_pic' in card['mblog']: image_path = path + str(count_weibo) # if os.path.exists(image_path) is False: os.mkdir(image_path) url_extend = 'https://m.weibo.cn/status/' + mid # 单条微博url res = requests.get(url_extend, headers=headers).text # str类型 imgurl_weibo = re.findall('https://.*large.*.jpg', res) # 用正则匹配到图片url x = 1 for iin range(len(imgurl_weibo)): temp = image_path + '/' + str(x) + '.jpg' # 将图片url添加到微博文本中 with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff: ff.write('微博图片链接:' + imgurl_weibo[i] + '\n') print('正在下载该条微博 第%s张图片' % x) try: urllib.request.urlretrieve(urllib.request.urlopen(imgurl_weibo[i]).geturl(), temp) except: print("该图片下载失败:%s" % imgurl_weibo) x += 1 with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff: ff.write(78 * '-' + '评论' + '>' + 78 * '-' + '\n') else: with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff: ff.write(78 * '-' + '评论' + '>' + 78 * '-' + '\n') count_weibo = count_weibo + 1 # 根据微博id获取热门评论,并输出 list_comments = self.getComments(mid, 1) # 评论只需要访问第一页 print('正在爬取该条微博 评论') count_hotcomments = 1 for comment in list_comments: # like_counts = comment['like_counts'] # 点赞数 text = comment['text'] # 评论内容 tree = html.fromstring(text) text = tree.xpath('string(.)') # 用string函数过滤掉多余标签 name_user = comment['user']['screen_name'] # 评论者的用户名 # 输出评论数据 if count_hotcomments<len(list_comments): with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff: result = str(count_hotcomments) + ': #' + name_user + '#' ff.write(result + '\n') ff.write(text + '\n\n') else: with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff: result = str(count_hotcomments) + ': #' + name_user + '#' ff.write(result + '\n') ff.write(text + '\n') count_hotcomments = count_hotcomments + 1 with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff: ff.write(78 * '-' + '<' + '评论' + 78 * '-' + '\n\n\n\n') time.sleep(2) print('暂停2秒\n') # 爬完一条微博的所有内容后 停顿两秒 page_weibo = page_weibo + 1 # 请求头,爬取新博主需更新Cookie和Referer headers = { 'Cookie': '_T_WM=5a5b9ae925e458f93279d6708b159927; ALF=1523107054; SCF=Ativ2ybI8StjZccoSRca_uyzfWFIcM45JHEaLQ_tD8ksmi6-whOM5Pl1p8Vz4EziyMQe5QgrSlo8RY9Nd3NiFO8.; SUB=_2A253pUizDeRhGeRG61EV9S_NwzuIHXVVZmj7rDV6PUJbktANLXD4kW1NTeA_GStZpY6CFmR1PzgN50YL186u9HbC; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9Wh2V9E8BT6Glu5-SxvF-MwO5JpX5K-hUgL.FozReheXSK2p1hM2dJLoI7D29PyXUGxXUsHE; SUHB=02M_R-ArnK_FEZ; WEIBOCN_FROM=1110006030; M_WEIBOCN_PARAMS=featurecode%3D20000320%26oid%3D3900009063730800%26luicode%3D10000011%26lfid%3D1076031195054531%26fid%3D1005051195054531%26uicode%3D10000011', 'Host': 'm.weibo.cn', # 'qq': 'MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1', 'Referer': 'https://m.weibo.cn/u/1195054531', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36', } crawl_weibo = CrawlWeibo() # 实例化爬虫类并调用成员方法进行输出 crawl_weibo.getAll('1195054531', 2, 'D:/weibo/') # 输入需要爬取用户uid,需要爬取微博页数,微博本地保存路径

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143

# -*- coding:utf-8 -*-'''Created on 2018年3月9日 @author: ora_jason'''from lxmlimport htmlimport requestsimport jsonimport reimport osimport timeimport urllib.request  class CrawlWeibo:# 获取指定博主的所有微博cards的listdefgetCards(self, id, page):  # id(字符串类型):博主的用户id;page(整型):微博翻页参数ii = 0list_cards = []while ii < page:            ii = ii + 1print('正在爬取第%d页cards' % ii)url = 'https://m.weibo.cn/api/container/getIndex?type=uid&value=' + id + '&containerid=107603' + id + '&page=' + str(                ii)            response = requests.get(url, headers=headers)ob_json = json.loads(response.text)  # ob_json为dict类型 list_cards.append(ob_json['data']['cards'])  # ob_json['data']['cards']为list类型time.sleep(2)print('暂停2秒')  # 爬完一页所有微博的cards后 停顿两秒return list_cards# 返回所有页的cards     # 获取某条微博的热门评论或评论的listdefgetComments(self, id, page):  # id(字符串类型):某条微博的id;page(整型):评论翻页参数url = 'https://m.weibo.cn/api/comments/show?id=' + id + '&page=' + str(page)        response = requests.get(url, headers=headers)ob_json = json.loads(response.text) list_comments = []if 'data' in ob_json:if 'hot_data' in ob_json['data']:list_comments = ob_json['data']['hot_data']else:list_comments = ob_json['data']['data']return list_comments# 返回某条微博下评论 defgetAll(self, id, page, path):  # id为博主uid,page为爬取页数,path为保存路径list_cards = self.getCards(id, page)print('爬取页数为:' + str(len(list_cards)) + '\n' + 30 * '-')count_weibo = 1page_weibo = 1# 遍历当页所有微博,保存内容,并根据id查找输出热门评论for cards in list_cards:for card in cards:if card['card_type'] == 9:  # 过滤出微博#if card['card_type'] == 9 and 'raw_text' not in card['mblog']:  # 过滤出原创微博print('正在爬取第' + str(page_weibo) + '页 第' + str(count_weibo) + '条card')                    mid = card['mblog']['id']created_at = card['mblog']['created_at']# 获取保存文本信息if card['mblog']['isLongText'] == 'false':                        text = card['mblog']['text']else:url = 'https://m.weibo.cn/statuses/extend?id=' + mid                        response = requests.get(url, headers=headers)ob_json = json.loads(response.text)  # ob_json为dict类型text = ob_json['data']['longTextContent']                    tree = html.fromstring(text)                    text = tree.xpath('string(.)')  # 用string函数过滤掉多余标签# 输出微博文本with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff:ff.write('第' + str(count_weibo) + '条\n' + '***  发布于  ' + created_at + '  ***' + '\n')ff.write(text + '\n') # 获取保存图片if 'bmiddle_pic' in card['mblog']:image_path = path + str(count_weibo)# if os.path.exists(image_path) is False:os.mkdir(image_path)url_extend = 'https://m.weibo.cn/status/' + mid  # 单条微博urlres = requests.get(url_extend, headers=headers).text  # str类型imgurl_weibo = re.findall('https://.*large.*.jpg', res)  # 用正则匹配到图片urlx = 1for iin range(len(imgurl_weibo)):                            temp = image_path + '/' + str(x) + '.jpg'# 将图片url添加到微博文本中with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff:ff.write('微博图片链接:' + imgurl_weibo[i] + '\n')print('正在下载该条微博 第%s张图片' % x)try:                                urllib.request.urlretrieve(urllib.request.urlopen(imgurl_weibo[i]).geturl(), temp)except:print("该图片下载失败:%s" % imgurl_weibo)                            x += 1with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff:ff.write(78 * '-' + '评论' + '>' + 78 * '-' + '\n')else:with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff:ff.write(78 * '-' + '评论' + '>' + 78 * '-' + '\n')count_weibo = count_weibo + 1 # 根据微博id获取热门评论,并输出list_comments = self.getComments(mid, 1)  # 评论只需要访问第一页print('正在爬取该条微博 评论')count_hotcomments = 1for comment in list_comments:# like_counts = comment['like_counts']  # 点赞数text = comment['text']  # 评论内容tree = html.fromstring(text)                        text = tree.xpath('string(.)')  # 用string函数过滤掉多余标签name_user = comment['user']['screen_name']  # 评论者的用户名# 输出评论数据if count_hotcomments<len(list_comments):with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff:                                result = str(count_hotcomments) + ': #' + name_user + '#'ff.write(result + '\n')ff.write(text + '\n\n')else:with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff:                                result = str(count_hotcomments) + ': #' + name_user + '#'ff.write(result + '\n')ff.write(text + '\n')count_hotcomments = count_hotcomments + 1with open(path + 'weibo_crawl.txt', 'a', encoding='utf-8') as ff:ff.write(78 * '-' + '<' + '评论' + 78 * '-' + '\n\n\n\n')time.sleep(2)print('暂停2秒\n')  # 爬完一条微博的所有内容后 停顿两秒page_weibo = page_weibo + 1  # 请求头,爬取新博主需更新Cookie和Refererheaders = {'Cookie': '_T_WM=5a5b9ae925e458f93279d6708b159927; ALF=1523107054; SCF=Ativ2ybI8StjZccoSRca_uyzfWFIcM45JHEaLQ_tD8ksmi6-whOM5Pl1p8Vz4EziyMQe5QgrSlo8RY9Nd3NiFO8.; SUB=_2A253pUizDeRhGeRG61EV9S_NwzuIHXVVZmj7rDV6PUJbktANLXD4kW1NTeA_GStZpY6CFmR1PzgN50YL186u9HbC; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9Wh2V9E8BT6Glu5-SxvF-MwO5JpX5K-hUgL.FozReheXSK2p1hM2dJLoI7D29PyXUGxXUsHE; SUHB=02M_R-ArnK_FEZ; WEIBOCN_FROM=1110006030; M_WEIBOCN_PARAMS=featurecode%3D20000320%26oid%3D3900009063730800%26luicode%3D10000011%26lfid%3D1076031195054531%26fid%3D1005051195054531%26uicode%3D10000011','Host': 'm.weibo.cn',# 'qq': 'MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1','Referer': 'https://m.weibo.cn/u/1195054531','Upgrade-Insecure-Requests': '1','User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36',} crawl_weibo = CrawlWeibo()  # 实例化爬虫类并调用成员方法进行输出crawl_weibo.getAll('1195054531', 2, 'D:/weibo/')  # 输入需要爬取用户uid,需要爬取微博页数,微博本地保存路径

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 MongoDB
腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档