职贝云数AI新零售门户

标题: 爬虫:新浪微博爬虫的最简单办法 [打印本页]

作者: VeUB7M    时间: 2023-1-4 00:27
标题: 爬虫:新浪微博爬虫的最简单办法
前言:本文次要内容是引见如何用最简单的办法去采集新浪微博的数据,次要是采集指定微博用户发布的微博以及微博收到的回复等内容,可以经过配置项来调整爬取的微博用户列表以及其他属性。
既然说是最简单的办法,那么我们就得先分析微博爬虫能够选择的几个目的网址,首先一定是最常见的web网站了

(, 下载次数: 1)

还有就是m站,也就是移动端网页

(, 下载次数: 0)

以及一个无法旧版本的访问入口了,首先可以扫除web站了,这个是最费事的,它的央求是被js加密过,处理起来很费事
那我们为何不退而求其次呢,我们观察下这个m站的央求

(, 下载次数: 1)

可以发如今某个央求里可以发现我们需求的微博信息,既然这样就好办了,我们就可以着手我们的代码了
首先是获取用户信息,经过用户信息获取用户的微博总数,这样就可以知道总共多少页的数据了,代码如下所示
  1. def get_json(self, params):
  2.         """获取网页中json数据"""
  3.         url = 'https://m.weibo.cn/api/container/getIndex?'
  4.         r = requests.get(url, params=params, cookies=self.cookie)
  5.         return r.json()
  6.     def get_page_count(self):
  7.         """获取微博页数"""
  8.         try:
  9.             weibo_count = self.user['statuses_count']
  10.             page_count = int(math.ceil(weibo_count / 10.0))
  11.             return page_count
  12.         except KeyError:
  13.             sys.exit(u'程序出错')
  14.     def get_user_info(self):
  15.         """获取用户信息"""
  16.         params = {'containerid': '100505' + str(weibo_config['user_id'])}
  17.         js = self.get_json(params)
  18.         if js['ok']:
  19.             info = js['data']['userInfo']
  20.             user_info = {}
  21.             user_info['id'] = weibo_config['user_id']
  22.             user_info['screen_name'] = info.get('screen_name', '')
  23.             user_info['gender'] = info.get('gender', '')
  24.             user_info['statuses_count'] = info.get('statuses_count', 0)
  25.             user_info['followers_count'] = info.get('followers_count', 0)
  26.             user_info['follow_count'] = info.get('follow_count', 0)
  27.             user_info['description'] = info.get('description', '')
  28.             user_info['profile_url'] = info.get('profile_url', '')
  29.             user_info['profile_image_url'] = info.get('profile_image_url', '')
  30.             user_info['avatar_hd'] = info.get('avatar_hd', '')
  31.             user_info['urank'] = info.get('urank', 0)
  32.             user_info['mbrank'] = info.get('mbrank', 0)
  33.             user_info['verified'] = info.get('verified', False)
  34.             user_info['verified_type'] = info.get('verified_type', 0)
  35.             user_info['verified_reason'] = info.get('verified_reason', '')
  36.             user = self.standardize_info(user_info)
  37.             self.user = user
复制代码
分页采集数据
  1. page1 = 0
  2.         random_pages = random.randint(1, 5)
  3.         self.start_date = datetime.now().strftime('%Y-%m-%d')
  4.         for page in tqdm(range(1, page_count + 1), desc='Progress'):
  5.             is_end = self.get_one_page(page)
  6.             if is_end:
  7.                 break
  8.             if page % 20 == 0:  # 每爬20页写入一次文件
  9.                 self.weibo_to_mysql(wrote_count)
  10.                 wrote_count = self.got_count
  11.             # 经过加入随机等待避免被限制。爬虫速度过快容易被系统限制(一段工夫后限
  12.             # 制会自动解除),加入随机等待模拟人的操作,可降低被系统限制的风险。默
  13.             # 认是每爬取1到5页随机等待6到10秒,假如照旧被限,可适当添加sleep工夫
  14.             if (page - page1) % random_pages == 0 and page < page_count:
  15.                 sleep(random.randint(6, 10))
  16.                 page1 = page
  17.                 random_pages = random.randint(1, 5)
  18.         self.weibo_to_mysql(wrote_count)  # 将剩余不足20页的微博写入文件
  19.         print(u'微博爬取完成,共爬取%d条微博' % self.got_count)
复制代码
详细采集单页微博代码如下
  1. def get_one_page(self, page):
  2.         """获取一页的全部微博"""
  3.         try:
  4.             js = self.get_weibo_json(page)
  5.             if js['ok']:
  6.                 weibos = js['data']['cards']
  7.                 for w in weibos:
  8.                     if w['card_type'] == 9:
  9.                         wb = self.get_one_weibo(w)
  10.                         if wb:
  11.                             if wb['id'] in self.weibo_id_list:
  12.                                 continue
  13.                             created_at = datetime.strptime(
  14.                                 wb['created_at'], '%Y-%m-%d')
  15.                             since_date = datetime.strptime(
  16.                                 self.since_date, '%Y-%m-%d')
  17.                             if created_at < since_date:
  18.                                 if self.is_pinned_weibo(w):
  19.                                     continue
  20.                                 else:
  21.                                     print(u'{}已获取{}({})的第{}页微博{}'.format(
  22.                                         '-' * 30, self.user['screen_name'],
  23.                                         self.user['id'], page, '-' * 30))
  24.                                     return True
  25.                             if ('retweet' not in wb.keys()):
  26.                                 self.weibo.append(wb)
  27.                                 self.weibo_id_list.append(wb['id'])
  28.                                 self.got_count += 1
  29.             print(u'{}已获取{}({})的第{}页微博{}'.format('-' * 30,
  30.                                                     self.user['screen_name'],
  31.                                                     self.user['id'], page,
  32.                                                     '-' * 30))
  33.         except Exception as e:
  34.             print("Error: ", e)
  35.             traceback.print_exc()
复制代码
获取详细微博信息的代码
  1. def get_one_weibo(self, info):
  2.         """获取一条微博的全部信息"""
  3.         try:
  4.             weibo_info = info['mblog']
  5.             weibo_id = weibo_info['id']
  6.             retweeted_status = weibo_info.get('retweeted_status')
  7.             is_long = weibo_info.get('isLongText')
  8.             if retweeted_status:  # 转发
  9.                 retweet_id = retweeted_status.get('id')
  10.                 is_long_retweet = retweeted_status.get('isLongText')
  11.                 if is_long:
  12.                     weibo = self.get_long_weibo(weibo_id)
  13.                     if not weibo:
  14.                         weibo = self.parse_weibo(weibo_info)
  15.                 else:
  16.                     weibo = self.parse_weibo(weibo_info)
  17.                 if is_long_retweet:
  18.                     retweet = self.get_long_weibo(retweet_id)
  19.                     if not retweet:
  20.                         retweet = self.parse_weibo(retweeted_status)
  21.                 else:
  22.                     retweet = self.parse_weibo(retweeted_status)
  23.                 retweet['created_at'] = self.standardize_date(
  24.                     retweeted_status['created_at'])
  25.                 weibo['retweet'] = retweet
  26.             else:  # 原创
  27.                 if is_long:
  28.                     weibo = self.get_long_weibo(weibo_id)
  29.                     if not weibo:
  30.                         weibo = self.parse_weibo(weibo_info)
  31.                 else:
  32.                     weibo = self.parse_weibo(weibo_info)
  33.             weibo['created_at'] = self.standardize_date(
  34.                 weibo_info['created_at'])
  35.             return weibo
  36.         except Exception as e:
  37.             print("Error: ", e)
  38.             traceback.print_exc()
  39.     def get_long_weibo(self, id):
  40.         """获取长微博"""
  41.         for i in range(5):
  42.             url = 'https://m.weibo.cn/detail/%s' % id
  43.             html = requests.get(url, cookies=self.cookie).text
  44.             html = html[html.find('"status":'):]
  45.             html = html[:html.rfind('"hotScheme"')]
  46.             html = html[:html.rfind(',')]
  47.             html = '{' + html + '}'
  48.             js = json.loads(html, strict=False)
  49.             weibo_info = js.get('status')
  50.             if weibo_info:
  51.                 weibo = self.parse_weibo(weibo_info)
  52.                 return weibo
  53.             sleep(random.randint(6, 10))
复制代码
以上就是核心的微博信息采集代码了,除了微博信息,我们还需求采集微博评论信息,原理是一样的,找到数据来源

(, 下载次数: 1)

有了微博信息采集的阅历,我们很容易就可以找到我们想要的那个接口
详细代码如下
  1. def add_comments_json(self,jsondata):
  2.         for data in jsondata:
  3.             item = dict()
  4.             item['id'] = data.get('id')
  5.             item['mid'] = data.get('mid')
  6.             item['like_count'] = data.get("like_count")
  7.             item['source'] = data.get("source")
  8.             item['floor_number'] = data.get("floor_number")
  9.             item['screen_name'] = data.get("user").get("screen_name")
  10.             # 性别
  11.             item['gender'] = data.get("user").get("gender")
  12.             if(item['gender'] == 'm'):
  13.                 item['gender'] = '男'
  14.             elif(item['gender'] == 'f'):
  15.                 item['gender'] = '女'
  16.             item['rootid'] = data.get("rootid")
  17.             item['create_time'] = data.get("created_at")
  18.             import time
  19.             item['create_time'] = time.strptime(item['create_time'], '%a %b %d %H:%M:%S %z %Y')
  20.             item['create_time'] = time.strftime('%Y-%m-%d',item['create_time'])
  21.             item['comment'] = data.get("text")
  22.             item['comment'] = BeautifulSoup(item['comment'], 'html.parser').get_text()
  23.             item['comment'] = self.clear_character_chinese(item['comment'])
  24.             print('当前楼层{},评论{}'.format(item['floor_number'],item['comment']))
  25.             # 评论这条评论的信息
  26.             comments = data.get("comments")
  27.             if(comments):
  28.                 self.add_comments_json(comments)
  29.             # print jsondata.dumps(comment, encoding="UTF-8", ensure_ascii=False)
  30.             self.comments.append(item)
  31.             
  32.     def get_comments_page(self,max_id, id_type,mid):
  33.         from get_weibo_cookie import get_cookie
  34.         params = {
  35.             'max_id': max_id,
  36.             'max_id_type': id_type
  37.             }
  38.         try:
  39.             url = 'https://m.weibo.cn/comments/hotflow?id={id}&mid={mid}&max_id='
  40.             headers = {
  41.             'Cookie': 'T_WM=96849642965; __guid=52195957.2500582256236055600.1583058027995.9556; WEIBOCN_FROM=1110006030; SCF=Aimq85D9meHNU4Ip0PFUjYBTDjXFB0VtQr3EKoS8DHQDobRNUO3lDIufAcUg69h4J7BQWqryxQpuU3ReIHHxvQ4.; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9W5H0p180lDMiCjNvXD_-uOh5JpX5KzhUgL.FoM0S0n0eo-0Sh.2dJLoI0qLxKqL1KMLBK-LxK-LBonLBonLxKMLB.-L12-LxK-LBK-LBoeLxK-L1hnL1hqLxKBLB.2LB-zt; XSRF-TOKEN=ca0a29; SUB=_2A25zWlwFDeRhGeFN7FoS8ivPzzWIHXVQpWRNrDV6PUJbkdANLW_9kW1NQ8CH90H5f8j5r1NA4GNPvu6__ERL-Jat; SUHB=0vJIkXXtLIIaZO; SSOLoginState=1583230037; MLOGIN=1; M_WEIBOCN_PARAMS=oid%3D4474164293517551%26luicode%3D20000174%26lfid%3D102803%26uicode%3D20000174; monitor_count=45',
  42.             'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
  43.             'X-Requested-With': 'XMLHttpRequest'
  44.         }
  45.             r = requests.get(url.format(id=mid,mid=mid), params=params,headers=headers)
  46.             print(r.url)
  47.             if r.status_code == 200:
  48.                 return r.json()
  49.         except requests.ConnectionError as e:
  50.             print('error', e.args)   
  51.    
  52.     def add_comments(self,jsondata):
  53.         datas = jsondata.get('data').get('data')
  54.         for data in datas:
  55.             item = dict()
  56.             item['id'] = data.get('id')
  57.             item['mid'] = data.get('mid')
  58.             item['like_count'] = data.get("like_count")
  59.             item['source'] = data.get("source")
  60.             item['floor_number'] = data.get("floor_number")
  61.             item['screen_name'] = data.get("user").get("screen_name")
  62.             # 性别
  63.             item['gender'] = data.get("user").get("gender")
  64.             if(item['gender'] == 'm'):
  65.                 item['gender'] = '男'
  66.             elif(item['gender'] == 'f'):
  67.                 item['gender'] = '女'
  68.             item['created_at'] = self.standardize_date(
  69.                 data.get(['created_at']))
  70.             import time
  71.             item['create_time'] = time.strptime(item['create_time'], '%a %b %d %H:%M:%S %z %Y')
  72.             item['create_time'] = time.strftime('%Y-%m-%d',item['create_time'])
  73.             item['rootid'] = data.get("rootid")
  74.             
  75.             item['comment'] = data.get("text")
  76.             item['comment'] = BeautifulSoup(item['comment'], 'html.parser').get_text()
  77.             item['comment'] = self.clear_character_chinese(item['comment'])
  78.             print('当前楼层{},评论{}'.format(item['floor_number'],item['comment']))
  79.             # 评论这条评论的信息
  80.             comments = data.get("comments")
  81.             # print jsondata.dumps(comment, encoding="UTF-8", ensure_ascii=False)
  82.             self.comments.append(item)
复制代码
我们可以查看下采集到的数据,如下所示

(, 下载次数: 0)

(, 下载次数: 0)

残缺代码可以去我的开源项目中查看或者下载,欢迎star,或者留言与我停止交流。
https://gitee.com/chengrongkai/OpenSpiders
本文收发于https://www.bizhibihui.com/blog/article/44
作者: ECCf2f    时间: 2023-1-4 00:28
大佬,可以帮忙爬取一个评论吗
作者: vpbBB    时间: 2023-1-4 00:29
怎么解决需要登录的问题
作者: jAwq    时间: 2023-1-4 00:29
爬评论需要登录,登录需要手机验证,怎么解?
作者: BXVHG    时间: 2023-1-4 00:29
微博登录问题怎么解决啊,一直没搞定这个
作者: CQPs1KQn    时间: 2023-1-4 00:30
感谢
作者: 5DlYsGu    时间: 2023-1-4 00:30
请问爬取的数据量有多少?一共用了多长时间呢?
作者: 2I7hqC    时间: 2023-1-4 00:30
国企爬新浪数据用于贸易,会不会呗高?
作者: BXVHG    时间: 2023-1-4 00:31
想请问一下可以爬取到每篇微博的阅读数量吗
作者: CQPs1KQn    时间: 2023-1-4 00:31
可以




欢迎光临 职贝云数AI新零售门户 (https://www.taojin168.com/cloud/) Powered by Discuz! X3.5