微博向来是一个极好的吃瓜圣地,为了获取微博上行行色色的数据,微博相关的爬虫也是层出不穷,由于不管是运营者仍是数据分析从业者都或多或少须要微博数据,个人许多朋友也不例外,通过断断续续的努力,我完成了一个多是史上最强大的微博爬虫的编写。html
该爬虫的功能主要分为三部分,第一个主打功能是爬取指定用户的全部微博(能够经过热键 Ctrl + P 快速打开),这个用户能够按照昵称搜索,能够选择是否只抓取原创微博,以下图
爬取的微博内容保存在 csv 文件中,表头包括微博id、微博正文、图片url、发布位置、发布时间、发布工具和点赞数、评论数、转发数,其中图片url里面是全部微博图片的url以英文逗号间隔拼接起来的。
第二个主打功能是爬取指定话题下的全部微博,以下图
微博保存的 csv 格式大体和爬取用户微博格式相似。web
第三个主打功能就是爬取根据微博id爬取该微博下的全部评论详情,好比微博 id 为 IaYZIu0Ko 的全部评论为:
除了爬虫的业务逻辑,你们也能够在上面看到,有较为友好的操做界面,方便你们操做。正则表达式
代码共计 1000 余行,不关心技术的同窗能够直接跳到文末获取程序连接。
爬虫部分主要是 经过 Chrome 分析微博页面上的接口,获取接口参数,使用 requests 库模拟请求,须要带上 cookies ,我这个爬虫的大头实际上是解析部分,我主要用了 lxml 库,须要解析的东西很是多,差很少 csv 中的每个字段都须要单独的代码块来解析。微信
爬虫实现的三个功能:按用户爬取、按话题爬取、爬取微博全部评论,我分别用了三个类来实现,WeiboUserScrapy、WeiboTopicScrapy、WeiboCommentScrapy,三个类都有一些能够复用的函数,可是为了减小类之间的耦合,以及方便打包,我没有复用,这样单独一个类拿出来也能跑,减小了依赖。cookie
再主要是界面模块的编写,我以前一直用 wxPython 编写界面,后来深刻学习了 pyqt5 这个库,因此这个爬虫的界面是用 pyqt5 来写的,这里主要用到了 ListView model-view模型、自定义信号及槽函数和一些常见组件的使用。多线程
爬虫比较耗时,而界面又不容许阻塞,因此必须采用多线程技术,使用自定义信号做为爬虫类和界面类之间沟通的桥梁,好比爬虫开始、结束都会向界面类发出相应的信号完成界面的更新。app
目前有个不完善的地方就是,后台任务除了进度框和打印,没有其余可视化查看的方法,并且各任务之间的调度只是简单的先到先服务,后续我会自定义调度器类,完成各类暂停、恢复、优先级处理等各类智能调度以及高级的可视化界面。svg
以 WeiboCommentScrapy 类为例,首先经过正则表达式获取评论总数,函数
res = requests.get('https://weibo.cn/comment/{}'.format(self.wid),headers=self.headers,verify=False) commentNum = re.findall("评论\[.*?\]",res.text)[0] commentNum = int(commentNum[3:len(commentNum)-1])
而后根据评论总数分页工具
pageNum = ceil(commentNum/10)
接着两层循环,外层遍历页数,内层遍历每一页的评论,最后对每个评论作解析
for page in range(pageNum): result = [] res = requests.get('https://weibo.cn/comment/{}?page={}'.format(self.wid,page+1), headers=self.headers,verify=False) html = etree.HTML(res.text.encode('utf-8')) comments = html.xpath("/html/body/div[starts-with(@id,'C')]") print('第{}/{}页'.format(page+1,pageNum)) for i in range(len(comments)): result.append(self.get_one_comment_struct(comments[i])) if page==0: self.write_to_csv(result,isHeader=True) else: self.write_to_csv(result,isHeader=False) # 休眠 1-5 秒,防止被封 sleep(randint(1,5))
注意看内层循环,看上去每一页都是 10 条评论,实则否则,好比第一页有热门评论,会超过 10 条,最后一页可能没有 10 条,因此内层循环没有用 for i in range(10): 而是 for i in range(len(comments)):。内层循环还调用了一个函数 get_one_comment_struct(),其做用是根据 xpath 获得的每一条 comment 元素解析获得咱们想要的数据,其中又递归调用了几个自定义解析函数,好比解析获得的时间是诸如“xxx分钟前"、“刚刚”,咱们须要进一步作字符串处理获得具体时间戳。
因为本爬虫都是用 lxml 库采用 xpath 解析的,里面我遇到了许许多多的实用技巧,会在后续博客作详细展开。
为了方便你们使用,我已经把程序打包成 exe ,脱离了 Python 环境运行,只须要在微信公众号后台回复 微博爬虫 便可得到,同时因为接口变化,我会按期升级程序,为防止失联可在后台回复 社群,加入微信粉丝团,便可及时获取程序更新。
微信公众号:月小水长