scrapy 爬取微博(五)【最新超详细解析】: 爬取微博文章

1 读取配置参数

爬取微博文章首先需要读取settings.py中的设置的配置变量,然后编写爬虫,读取的配置变量主要有爬取的关键词、时间范围、爬取区域等。

class WeiboSearchSpider(scrapy.Spider):name = 'weibo_search'allowed_domains = ['weibo.com']settings = get_project_settings()keyword_list = settings.get('KEYWORD_LIST')if not isinstance(keyword_list, list):if not os.path.isabs(keyword_list):keyword_list = os.getcwd() + os.sep + keyword_listif not os.path.isfile(keyword_list):sys.exit('不存在%s文件' % keyword_list)keyword_list = utils.get_keyword_list(keyword_list)for i, keyword in enumerate(keyword_list):if len(keyword) > 2 and keyword[0] == '#' and keyword[-1] == '#':keyword_list[i] = '%23' + keyword[1:-1] + '%23'weibo_type = utils.convert_weibo_type(settings.get('WEIBO_TYPE'))contain_type = utils.convert_contain_type(settings.get('CONTAIN_TYPE'))regions = utils.get_regions(settings.get('REGION'))base_url = 'https://s.weibo.com'start_date = settings.get('START_DATE',datetime.now().strftime('%Y-%m-%d'))end_date = settings.get('END_DATE', datetime.now().strftime('%Y-%m-%d'))if utils.str_to_time(start_date) > utils.str_to_time(end_date):sys.exit('settings.py配置错误,START_DATE值应早于或等于END_DATE值,请重新配置settings.py')further_threshold = settings.get('FURTHER_THRESHOLD', 46)mysql_error = Falsepymysql_error = False

2 start_requests

负责发送请求的start_requests

  def start_requests(self):start_date = datetime.strptime(self.start_date, '%Y-%m-%d')end_date = datetime.strptime(self.end_date,'%Y-%m-%d') + timedelta(days=1)start_str = start_date.strftime('%Y-%m-%d') + '-0'end_str = end_date.strftime('%Y-%m-%d') + '-0'for keyword in self.keyword_list:if not self.settings.get('REGION') or '全部' in self.settings.get('REGION'):base_url = 'https://s.weibo.com/weibo?q=%s' % keywordurl = base_url + self.weibo_typeurl += self.contain_typeurl += '&timescope=custom:{}:{}'.format(start_str, end_str)print(f'url:{url}')yield scrapy.Request(url=url,callback=self.parse,meta={'base_url': base_url,'keyword': keyword})else:for region in self.regions.values():base_url = ('https://s.weibo.com/weibo?q={}&region=custom:{}:1000').format(keyword, region['code'])url = base_url + self.weibo_typeurl += self.contain_typeurl += '&timescope=custom:{}:{}'.format(start_str, end_str)# 获取一个省的搜索结果yield scrapy.Request(url=url,callback=self.parse,meta={'base_url': base_url,'keyword': keyword,'province': region})

3 parse

负责解析页面上元素的parse方法

 def parse(self, response):base_url = response.meta.get('base_url')keyword = response.meta.get('keyword')province = response.meta.get('province')is_empty = response.xpath('//div[@class="card card-no-result s-pt20b40"]')page_count = len(response.xpath('//ul[@class="s-scroll"]/li'))if is_empty:print('当前页面搜索结果为空')elif page_count < self.further_threshold:# 解析当前页面for weibo in self.parse_weibo(response):self.check_environment()yield weibonext_url = response.xpath('//a[@class="next"]/@href').extract_first()if next_url:next_url = self.base_url + next_urlyield scrapy.Request(url=next_url,callback=self.parse_page,meta={'keyword': keyword})else:start_date = datetime.strptime(self.start_date, '%Y-%m-%d')end_date = datetime.strptime(self.end_date, '%Y-%m-%d')while start_date <= end_date:start_str = start_date.strftime('%Y-%m-%d') + '-0'start_date = start_date + timedelta(days=1)end_str = start_date.strftime('%Y-%m-%d') + '-0'url = base_url + self.weibo_typeurl += self.contain_typeurl += '&timescope=custom:{}:{}&page=1'.format(start_str, end_str)# 获取一天的搜索结果yield scrapy.Request(url=url,callback=self.parse_by_day,meta={'base_url': base_url,'keyword': keyword,'province': province,'date': start_str[:-2]})

4 parse_weibo

解析微博内容

    def parse_weibo(self, response):"""解析网页中的微博信息"""keyword = response.meta.get('keyword')for sel in response.xpath("//div[@class='card-wrap']"):info = sel.xpath("div[@class='card']/div[@class='card-feed']/div[@class='content']/div[@class='info']")if info:weibo = WeiboItem()weibo['mid'] = sel.xpath('@mid').extract_first()bid = sel.xpath('.//div[@class="from"]/a[1]/@href').extract_first().split('/')[-1].split('?')[0]weibo['bid'] = bidweibo['user_id'] = info[0].xpath('div[2]/a/@href').extract_first().split('?')[0].split('/')[-1]weibo['screen_name'] = info[0].xpath('div[2]/a/@nick-name').extract_first()txt_sel = sel.xpath('.//p[@class="txt"]')[0]retweet_sel = sel.xpath('.//div[@class="card-comment"]')retweet_txt_sel = ''if retweet_sel and retweet_sel[0].xpath('.//p[@class="txt"]'):retweet_txt_sel = retweet_sel[0].xpath('.//p[@class="txt"]')[0]content_full = sel.xpath('.//p[@node-type="feed_list_content_full"]')is_long_weibo = Falseis_long_retweet = Falseif content_full:if not retweet_sel:txt_sel = content_full[0]is_long_weibo = Trueelif len(content_full) == 2:txt_sel = content_full[0]retweet_txt_sel = content_full[1]is_long_weibo = Trueis_long_retweet = Trueelif retweet_sel[0].xpath('.//p[@node-type="feed_list_content_full"]'):retweet_txt_sel = retweet_sel[0].xpath('.//p[@node-type="feed_list_content_full"]')[0]is_long_retweet = Trueelse:txt_sel = content_full[0]is_long_weibo = Trueweibo['text'] = txt_sel.xpath('string(.)').extract_first().replace('\u200b', '').replace('\ue627', '')weibo['article_url'] = self.get_article_url(txt_sel)weibo['location'] = self.get_location(txt_sel)if weibo['location']:weibo['text'] = weibo['text'].replace('2' + weibo['location'], '')weibo['text'] = weibo['text'][2:].replace(' ', '')if is_long_weibo:weibo['text'] = weibo['text'][:-4]weibo['at_users'] = self.get_at_users(txt_sel)weibo['topics'] = self.get_topics(txt_sel)reposts_count = sel.xpath('.//a[@action-type="feed_list_forward"]/text()').extract()reposts_count = "".join(reposts_count)try:reposts_count = re.findall(r'\d+.*', reposts_count)except TypeError:print("无法解析转发按钮,可能是 1) 网页布局有改动 2) cookie无效或已过期。\n""请在 https://github.com/dataabc/weibo-search 查看文档,以解决问题,")raise CloseSpider()weibo['reposts_count'] = reposts_count[0] if reposts_count else '0'comments_count = sel.xpath('.//a[@action-type="feed_list_comment"]/text()').extract_first()comments_count = re.findall(r'\d+.*', comments_count)weibo['comments_count'] = comments_count[0] if comments_count else '0'attitudes_count = sel.xpath('.//a[@action-type="feed_list_like"]/button/span[2]/text()').extract_first()attitudes_count = re.findall(r'\d+.*', attitudes_count)weibo['attitudes_count'] = attitudes_count[0] if attitudes_count else '0'created_at = sel.xpath('.//div[@class="from"]/a[1]/text()').extract_first().replace(' ', '').replace('\n', '').split('前')[0]weibo['created_at'] = utils.standardize_date(created_at)source = sel.xpath('.//div[@class="from"]/a[2]/text()').extract_first()weibo['source'] = source if source else ''pics = ''is_exist_pic = sel.xpath('.//div[@class="media media-piclist"]')if is_exist_pic:pics = is_exist_pic[0].xpath('ul[1]/li/img/@src').extract()pics = [pic[8:] for pic in pics]pics = [re.sub(r'/.*?/', '/large/', pic, 1) for pic in pics]pics = ['https://' + pic for pic in pics]video_url = ''is_exist_video = sel.xpath('.//div[@class="thumbnail"]//video-player').extract_first()if is_exist_video:video_url = re.findall(r'src:\'(.*?)\'', is_exist_video)[0]video_url = video_url.replace('&amp;', '&')video_url = 'http:' + video_url# if not retweet_sel:#     weibo['pics'] = pics#     weibo['video_url'] = video_url# else:#     weibo['pics'] = ''#     weibo['video_url'] = ''weibo['retweet_id'] = ''if retweet_sel and retweet_sel[0].xpath('.//div[@node-type="feed_list_forwardContent"]/a[1]'):retweet = WeiboItem()retweet['id'] = retweet_sel[0].xpath('.//a[@action-type="feed_list_like"]/@action-data').extract_first()[4:]retweet['bid'] = retweet_sel[0].xpath('.//p[@class="from"]/a/@href').extract_first().split('/')[-1].split('?')[0]info = retweet_sel[0].xpath('.//div[@node-type="feed_list_forwardContent"]/a[1]')[0]retweet['user_id'] = info.xpath('@href').extract_first().split('/')[-1]retweet['screen_name'] = info.xpath('@nick-name').extract_first()retweet['text'] = retweet_txt_sel.xpath('string(.)').extract_first().replace('\u200b','').replace('\ue627', '')retweet['article_url'] = self.get_article_url(retweet_txt_sel)retweet['location'] = self.get_location(retweet_txt_sel)if retweet['location']:retweet['text'] = retweet['text'].replace('2' + retweet['location'], '')retweet['text'] = retweet['text'][2:].replace(' ', '')if is_long_retweet:retweet['text'] = retweet['text'][:-4]retweet['at_users'] = self.get_at_users(retweet_txt_sel)retweet['topics'] = self.get_topics(retweet_txt_sel)reposts_count = retweet_sel[0].xpath('.//ul[@class="act s-fr"]/li[1]/a[1]/text()').extract_first()reposts_count = re.findall(r'\d+.*', reposts_count)retweet['reposts_count'] = reposts_count[0] if reposts_count else '0'comments_count = retweet_sel[0].xpath('.//ul[@class="act s-fr"]/li[2]/a[1]/text()').extract_first()comments_count = re.findall(r'\d+.*', comments_count)retweet['comments_count'] = comments_count[0] if comments_count else '0'attitudes_count = retweet_sel[0].xpath('.//a[@class="woo-box-flex woo-box-alignCenter woo-box-justifyCenter"]//span[@class="woo-like-count"]/text()').extract_first()attitudes_count = re.findall(r'\d+.*', attitudes_count)retweet['attitudes_count'] = attitudes_count[0] if attitudes_count else '0'created_at = retweet_sel[0].xpath('.//p[@class="from"]/a[1]/text()').extract_first().replace(' ', '').replace('\n', '').split('前')[0]retweet['created_at'] = utils.standardize_date(created_at)source = retweet_sel[0].xpath('.//p[@class="from"]/a[2]/text()').extract_first()retweet['source'] = source if source else ''# retweet['pics'] = pics# retweet['video_url'] = video_urlretweet['retweet_id'] = ''yield {'weibo': retweet, 'keyword': keyword}weibo['retweet_id'] = retweet['id']weibo["ip"] = self.get_ip(bid)avator = sel.xpath("div[@class='card']/div[@class='card-feed']/div[@class='avator']")if avator:user_auth = avator.xpath('.//svg/@id').extract_first()print(user_auth)if user_auth == 'woo_svg_vblue':weibo['user_authentication'] = '蓝V'elif user_auth == 'woo_svg_vyellow':weibo['user_authentication'] = '黄V'elif user_auth == 'woo_svg_vorange':weibo['user_authentication'] = '红V'elif user_auth == 'woo_svg_vgold':weibo['user_authentication'] = '金V'else:weibo['user_authentication'] = '普通用户'print(weibo)weibo['keywords'] = keywordyield {'weibo': weibo, 'keyword': keyword}

5 运行情况

我们爬取的关键词是:[‘华为’, ‘苹果公司’]
爬取的时间范围是:2024年9月1日~9月30日
运行效果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/436952.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows 环境下 MySQL5.5 安装与配置详解

Windows 环境下 MySQL5.5 安装与配置详解 目录 Windows 环境下 MySQL5.5 安装与配置详解一、MySQL 软件的下载二、安装 MySQL三、配置 MySQL1、配置环境变量2、安装并启动 MySQL 服务3、设置 MySQL 字符集4、为 root 用户设置登录密码 一、MySQL 软件的下载 1、登录网址&#…

基于Springboot+Vue的《计算机基础》网上考试系统(含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统中…

github项目--crawl4ai

github项目--crawl4ai 输出html输出markdown格式输出结构化数据与BeautifulSoup的对比 crawl4ai github上这个项目&#xff0c;没记错的话&#xff0c;昨天涨了3000多的star&#xff0c;今天又新增2000star。一款抓取和解析工具&#xff0c;简单写个demo感受下 这里我们使用cra…

ThreadLocal内存泄漏分析

一、ThreadLocal内存泄漏分析 1.1 ThreadLocal实现原理 1.1.1、set(T value)方法 查看ThreadLocal源码的 set(T value)方法&#xff0c;可以发现数据是存在了ThreadLocalMap的静态内部类Entry里面 其中key为使用弱引用的ThreadLocal实例&#xff0c;value为set传入的值。核…

031集——文本文件按空格分行——C#学习笔记

如下图&#xff0c;读取每行文本&#xff0c;每行文本再按空格分开读取一个字符串&#xff0c;输出到另一个文本&#xff1a; CAD环境下&#xff0c;代码如下&#xff1a; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Runtime; using System; using Sys…

deepin 无线网络搜不到信号

搜索不到wifi信号和无法连接wifi&#xff0d;论坛&#xff0d;深度科技 (deepin.org)https://bbs.deepin.org/zh/post/218198

Python编码系列—Python责任链模式:打造灵活的请求处理流程

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

华为开源自研AI框架昇思MindSpore应用案例:计算高效的卷积模型ShuffleNet

如果你对MindSpore感兴趣&#xff0c;可以关注昇思MindSpore社区 ShuffleNet ShuffleNet网络介绍 ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型&#xff0c;和MobileNet, SqueezeNet等一样主要应用在移动端&#xff0c;所以模型的设计目标就是利用有限的计算资源来达到…

解决VRM格式模型在Unity中运行出现头发乱飞等问题

1、问题 通过VRoidStudio制作导出的vrm格式的模型&#xff0c;放在unity中使用时&#xff0c;一运行就会出现头发乱飞&#xff0c;没有自然下垂的问题 2、解决方法 将模型下的secondary中的所有VRM Spring Bone脚本中的Drag Force改为1&#xff0c;Hit Radius改为0 修改后…

自定义注解加 AOP 实现服务接口鉴权以及内部认证

注解 何谓注解&#xff1f; 在Java中&#xff0c;注解&#xff08;Annotation&#xff09;是一种特殊的语法&#xff0c;用符号开头&#xff0c;是 Java5 开始引入的新特性&#xff0c;可以看作是一种特殊的注释&#xff0c;主要用于修饰类、方法或者变量&#xff0c;提供某些信…

基于定制开发与2+1链动模式的商城小程序搭建策略

摘要&#xff1a;本文探讨商城小程序的搭建策略&#xff0c;对比自主组建团队和第三方开发两种方式&#xff0c;强调以第三方开发模式为主的优势。阐述在第三方开发模式下&#xff0c;结合定制开发和21链动模式&#xff0c;如何搭建一款有助于企业商业模式创新与智能商业升级的…

【韩顺平Java笔记】第5章:程序控制结构

文章目录 102. 回顾上一章节103. 顺序控制103.1 顺序控制 104. 单分支使用104.1 分支控制 if-else 介绍104.2 单分支 105. 单分支流程图106. 双分支使用107. 双分支流程图108. 双分支练习题109. 多分支使用109.1 多分支的流程图 110. 多分支练习1111. 多分支练习2112. 嵌套分支…

大数据-151 Apache Druid 集群模式 配置启动【上篇】 超详细!

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

网络通信——OSPF协议(基础篇)

这里基础是因为没有讲解OSPF中的具体算法过程&#xff0c;以及其中很多小细节。后续会更新。 目录 一.OSPF的基础信息 二.认识OSPF中的Router ID 三.OSPF中的三张表 四.OSPF中的度量方法&#xff08;计算开销值&#xff09; 五. OSPF选举DR和BDR&#xff08;就是这个区域…

Leetcode3295. 举报垃圾信息

Every day a Leetcode 题目来源&#xff1a;3295. 举报垃圾信息 解法1&#xff1a;哈希 将字符串数组 bannedWords 的字符串保存在一个哈希表里。 遍历字符串数组 message 的每一个字符串 mes&#xff0c;如果 mes 在哈希表中出现&#xff0c;count。 如果 count > 2&a…

剪刀面的做法

1 面和水称重准备好&#xff0c;鸡蛋敲孔流入面粉中两个蛋清。 2 边下水边和面&#xff0c;每次下水不要太多&#xff0c;这是和硬面要注意的&#xff0c;下水多&#xff0c;水用完了&#xff0c;面还没和起来&#xff0c;一边揉面一边搓面盆周围&#xff0c;这样可以使盆光&a…

WebRTC入门

主要参考资料&#xff1a; WebRTC 在 ESP32 系列硬件平台上的实现: https://www.bilibili.com/video/BV1AEHseWEda/?spm_id_from333.337.search-card.all.click&vd_sourcedd284033cd0c4d1f3f59a2cd40ae4ef9 火山 RTC豆包大模型&#xff0c;给用户体验装上银色子弹: https:…

python的内存管理机制

python的内存管理机制主要分为三个部分&#xff1a;引用计数、垃圾回收和内存池机制。 引用计数机制&#xff1a; python通过维护每个对象的引用计数来跟踪内存中的对象。当对象被创建时就会有一个引用计数&#xff0c;当对象不再被使用时&#xff0c;引用计数为0&#xff0c…

SSE的使用

文章目录 SSE的使用前提需求SSE简介使用demo客户端&#xff08;HTML&#xff09;服务端 SSE API常用方法&#xff1a;事件&#xff1a;自定义关联事件&#xff1a; 服务端数据处理 SSE的使用 前提需求 web开发过程中需要前后端进行实时数据或者定时数据推送的需求中&#xff…

WebSocket消息防丢ACK和心跳机制对信息安全性的作用及实现方法

WebSocket消息防丢ACK和心跳机制对信息安全性的作用及实现方法 在现代即时通讯&#xff08;IM&#xff09;系统和实时通信应用中&#xff0c;WebSocket作为一种高效的双向通信协议&#xff0c;得到了广泛应用。然而&#xff0c;在实际使用中&#xff0c;如何确保消息的可靠传输…