Pyppeteer爬取移动端微博评论区简单案例
在简单学习了Pyppeteer之后,就想利用其来实现一个爬取实战来巩固知识,也是为了做点东西,让学的东西不那么空洞。
然后选取了微博评论区进行爬取。
但是在复制网页端的微博的节点的Selector并进行查找的时候,发现怎么都找不到。(这个问题我暂时也不知道什么情况)
于是,在这种情况下,我选择了移动端的微博,(好像确实要容易爬取一些)
以下是我在写程序时记录的一些问题及解决吧(应该算日志吧):
"""思路:先进入wb网页,然后利用选择器点击每个动态下面的评论,接着获取查看全部评论的href,然后拼凑成新的url,进入动态的详情页,然后爬取里面的评论。爬取评论包含:用户名,评论内容,ip地址然后在分别把所有评论用逗号分隔,拼凑成一个文本,进行文本词频统计生成词云,用AG图片作为词云形状同理对用户名和ip地址进行操作 - 3.14
""""""-3.16
问题:solved-1.网页版的微博在爬取的时候,使用复制过来的Selector会报错,显示找不到节点,没有找到解决方案,于是转向爬取移动端的微博网页.solved-2. click函数如何使用才会跳转。unsolved-3. click在使用该函数之后并没有在显示的界面上跳转,还需要手动点击一下,函数才开始运行,暂未得到解决. ####################(还未解决) ------> solved : 换选择器,点微博正文也能跳转(3.20)solved-4. 在跳转到动态的详情页之后,如何让网页往下滑成了新的问题.在大量搜索后仍然没有找到解决方案,然后寻求Pyppeteer的API,发现里面也没有对应的方法可以使用,最后想到了可以通过键盘的PageDown键来进行下滑操作.但这样做有缺点,首先就是不知道要获取全部评论要按多少次PageDown键,其次是这样做好像有一点耗时。solved-5. 但是在下滑时,如果滑到新评论,需要进行登录,本来想要使用模拟登录来解决该问题,然后想起来pyppeter的launch里面有可以记录登录状态的参数,于是先模拟一次打开界面,然后停留一段时间进行登录,从而使得登录状态的数据被保存下来。在后面的下滑网页的操作中不再需要操作。to-be-solved-6. 在获取评论信息并分类时,发现存在一些数组越界问题,于是采用“列表推导 if else”的结构来解决这种情况。同时对于没有获取到的评论,使用"暂无"来代替,这在后面进行词频统计的时候要剔除掉该词。########################(需要解决) ---------> solved: 通过查看网页结构发现,在评论出现表情或者图片的时候,评论内容会在标签h3下面在延伸.解决方法就是用户名和评论内容分别获取,一个用h4标签, 一个用h3标签。
Now: 1.现在已经可以爬取一个动态里面的部分评论,并进行分类存储在一个字典里面,仍需储存在一个文件里面。 -> solved(3.20)2.现在还需要事先获取每条动态的评论数,从而得到每次下滑网页按键的次数。 -> solved(3.20)3.还需要设置动态页的按键次数,从而获取更多的动态 ->solved(3.20)4.还需要能够爬取多条动态。 ->solved(3.20)5.现在使用BASIC_URL_2,SELECTOR_BASIC_2
函数(现有):1.初始化2.爬取URL3.点击评论进入详情页4.解析详情页评论信息3.20:5. 保存数据到文件里面6. 获取更多动态7. 获取文件内容并进行分词后的结果8. 设置屏幕尺寸为全屏更新思路:路:先进入wb网页,然后利用选择器点击每个动态下面的评论按钮,进入动态的详情页,不断下滑获取更多评论,然后爬取里面的评论。同时网页也需要下滑操作来获取更多的动态。爬取评论包含:用户名,评论内容,ip地址然后在分别把所有评论用逗号分隔,拼凑成一个文本,进行文本词频统计生成词云,用AG图片作为词云形状同理对用户名和ip地址进行操作 - 3.16
""""""-3.20
日志更新库:1. logging2. 在经过初始化设置后,用logging.info输出的信息带有时间,可以把logging.info当成一个print来用3. 初始化设置:logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s : %(message)s')
中文分词库:1. jieba词云设置:
# w=wordcloud.WordCloud(font_path='msyh.ttc',width=800,height=600,max_words=150,font_step=2,stopwords=stopwords,collocations=False)1. font_path :表示字体路径,可以从C->Windows->Fonts 获取。2. width: 输出画布的宽度3. height: 输出画布的高度4. max_words: 画布里面显示词数的最大数5. font_path: 字体步长6. stopwords: 停用词,表示需要屏蔽的词,在这里用了中文的停用词,防止一些特殊符号影响输出。7. collocations: 将参数设置为False,防止关键词出现重复的现象。
词云常规函数:1. w.generate(txt) #向 WordCloud 对象 w 中加载文本 txt2. w.to_file(PNG_PATH.format(str=FIlE_NAME[i])) # 将词云输出为图像文件 .jpg或.png文件
"""
下面是源代码:
import logging
import tkinter
from pyppeteer.errors import TimeoutError
from wordcloud import WordCloud
import asyncio
from pyppeteer import launch
from pyquery import PyQuery as pq# 词频统计
import jieba
import wordcloud
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s : %(message)s')
TIMEOUT = 10
DOWN_NUMBER = 260 # 动态页按下的次数
BEGIN_NUMBER = 4 # 开始动态的index
END_NUMBER = 50 # 结束动态的index
FILE_PATH = "./KPL-COMMENT/{str}.txt" # 保存文件路径
PNG_PATH = "./KPL-COMMENT/{str}.png"
FIlE_NAME = ["comments","ip","user_names"] # 储存三个文件名# WINDOW_WIDTH, WINDOW_HEIGHT = 1366, 768
HEADLESS = False
BASIC_URL = "https://weibo.com/agcwh"
COMMENT_URL = "https://weibo.com{comment_url}"
SELECTOR_BASIC = "#scroller > div.vue-recycle-scroller__item-wrapper > div:nth-child(1) > div > article > footer > div > div:nth-child(2) > div > span"BASIC_URL_2 = "https://m.weibo.cn/u/5878848794?uid=5878848794&t=0&luicode=10000011&lfid=100103type%3D1%26q%3Dag%E8%B6%85%E7%8E%A9%E4%BC%9A" # 实际用到的网页链接
SELECTOR_BASIC_2 = "#app > div:nth-child(1) > div:nth-child(1) > div:nth-child({index}) > div > div > div > footer > div:nth-child(3) > h4" # 实际用到的评论内容选择器SELECTOR_BASIC_3 ="#app > div:nth-child(1) > div:nth-child(1) > div:nth-child({index}) > div > div > div > article > div.weibo-og > div.weibo-text" # 实际用到的点击用的选择器
#app > div:nth-child(1) > div:nth-child(1) > div:nth-child(4) > div > div > div > article > div.weibo-og > div.weibo-text
# index从4开始,这是点击评论的selector# 设置中文停用词
stopwords = set()
content = [line.strip() for line in open('stop_words.txt','r',encoding='utf-8').readlines()]
stopwords.update(content)browser, page = None, Nonedef screen_size():# 设置屏幕尺寸为全屏tk = tkinter.Tk()width = tk.winfo_screenwidth()height = tk.winfo_screenheight()tk.quit()return {'width': width, 'height': height}async def init( ):global browser, pagebrowser = await launch(headless=HEADLESS, userDataDir='./userdata', args=['--start-maximized','--disable-infobars'])#网页全屏page = await browser.newPage()await page.setViewport(screen_size())await page.evaluateOnNewDocument('Object.defineProperty(navigator,"webdriver",{get:()=>undefined})')# 隐藏WebDriver信息,防止被拦截await page.setJavaScriptEnabled(enabled=True)async def scrape(url, selector):"""爬取网页的基本操作"""logging.info("Scraping %s...", url)try:await page.goto(url)await page.waitForSelector(selector, options={'timeout':TIMEOUT * 100})except :logging.error("Error occurred while scraping %s", url, exc_info=True)async def click_comment(index):"""点击微博正文从而进入相应的详情页"""global pageselector = SELECTOR_BASIC_2.format(index=index)# await scrape(BASIC_URL_2, selector=selector)count = await get_count(selector)selector = SELECTOR_BASIC_3.format(index=index)# 这是微博正文的Selector,可以点击,但是评论的数字点不了try:await asyncio.gather( # 先等待后跳转page.waitForNavigation(), # 等待页面跳转函数page.click(selector,options={'button':'left','delay':1}))except :logging.info("No node found for selector.....")await get_comment(count)# 复制过来的微博评论用户名的Selector
#app > div:nth-child(1) > div:nth-child(1) > div:nth-child(6) > div > div > div > footer > div:nth-child(3) > h4
# 复制过来的微博正文的Selector
#app > div:nth-child(1) > div:nth-child(1) > div:nth-child(5) > div > div > div > article > div.weibo-og > div.weibo-text
async def get_count(selector):"""获取每条动态的评论数"""# await scrape(BASIC_URL_2, selector=selector)try:await page.waitForSelector(selector, options={'timeout':TIMEOUT * 100})except TimeoutError:logging.error("Error occurred while scraping ...", exc_info=True)doc = pq(await page.content())count = doc(selector).text() # 获取的count为str类型print(count)if count:return int(count)else :return 260async def get_comment(count):"进入详情页之后,先利用键盘下滑,然后爬取评论数据"for i in range(count):# 把评论数乘以10作为按下ArrowDown键的次数,这样仍不能够实现完全获取全部评论的效果,但可以获取大部分# 利用键盘上的ArrowDown键,或者叫做PageDown键,来实现网页不断往下滑,不断更新内容的功能await page.keyboard.press('ArrowDown')try: #有时会莫名其妙出一些找不到结点的问题(我也不知道为什么),用try except解决await page.waitForSelector(".comment-content ", options={'timeout':TIMEOUT * 100})except:logging.info("TimeoutError")doc = pq(await page.content())# messages = [item.text().split('\n') for item in doc(".comment-content .m-text-box ").items()] names = [item.text() for item in doc(".comment-content .m-text-box h4").items()]comments = [item.text() for item in doc(".comment-content .m-text-box h3").items()]# 由于网页结构关系,每条评论的用户名和评论内容的文本可以一块获取,所以messages数组储存每条评论的用户名和评论内容,后面再分开ips = [item.text().split() for item in doc(".comment-content .time").items()]# ip地址和发布时间的文本连在一块,这里把每条评论的发布时间和ip地址用spilt分开,以便后续储存ip地址try:comment_info={'user_names' : names,'comments':comments,'ip':[ips[i][-1][2:] for i in range(len(ips))]# 这里面利用切片[2:] 把ip地址里面的“来自”两个字删掉 ,同时考虑了数组下标越界的情况(其实是因为在运行时存在越界情况导致出错,所以需要进行改善)}except IndexError :logging.info("ips:%s",ips)logging.info("出现数组下标越界情况,后面评论暂不爬取")# 用comment_info这样一个字典来存储获取的评论信息for i in range(3):await save_data(FIlE_NAME[i], comment_info[FIlE_NAME[i]])# logging.info(comment_info)# logging.info(len(messages))async def get_more(): #等到某动作完成"""获取更多的动态,其实质是先不断往下滑,让网页加载更多内容"""await page.goto(BASIC_URL_2)for i in range(DOWN_NUMBER):# 把评论数乘以10作为按下ArrowDown键的次数,这样仍不能够实现完全获取全部评论的效果,但可以获取大部分# 利用键盘上的ArrowDown键,或者叫做PageDown键,来实现网页不断往下滑,不断更新内容的功能await page.keyboard.press('ArrowDown')async def save_data(str, data):"""保存数据"""file_name = FILE_PATH.format(str=str)with open(file_name, "a", encoding="utf-8") as f:f.write(','.join(data))async def get_text(filename):"""获取文件中的内容,并用中文分词库进行分词后返回"""f = open(filename, "r", encoding='utf-8')txt = f.read()f.close()txt=' '.join(jieba.lcut(txt))return txtasync def main():await init()await page.goto(BASIC_URL_2)await get_more()while True : for i in range(BEGIN_NUMBER, END_NUMBER+1):await click_comment(i)logging.info("Scraping number:%d......",i-3)# await click_comment(5)for i in range(3):txt = await get_text(FILE_PATH.format(str=FIlE_NAME[i]))logging.info("txt:%s",txt)print(type(txt))w=wordcloud.WordCloud(font_path='msyh.ttc',width=800,height=600,max_words=150,font_step=2,stopwords=stopwords,collocations=False)w.generate(txt)w.to_file(PNG_PATH.format(str=FIlE_NAME[i]))logging.info('make wordCloud successfully!')breakawait browser.close()asyncio.get_event_loop().run_until_complete(main())
运行结束就会在同级文件夹下一个KPL-COMMENT的文件夹,文件夹下面出现三个文本文件,三个图片文件。
图片效果一览:
comments.png
ip.png
user_names.png
写在最后:
爬取的时候有一点没有考虑,那就是每条评论的回复评论,这点我没有进行爬取。
由于本人确实水平有限,所以写的仍不够完善,写这篇博客只是为了记录我自己写的一个案例。当然如果对大家有帮助那是最好不过了。如果有大佬指正问题,随时欢迎喔
Pyppeteer爬取移动端微博评论区简单案例相关推荐
- python爬取微博评论并做词频分析_爬取李子柒微博评论并分析
爬取李子柒微博评论并分析 微博主要分为网页端.手机端和移动端.微博网页版反爬太厉害,因此选择爬取手机端. 1 需求 爬取李子柒微博中视频的评论信息,并做词频分析. 2 方法 2.1 运行环境 运行平台 ...
- 爬取李子柒微博评论并分析
爬取李子柒微博评论并分析 微博主要分为网页端.手机端和移动端.微博网页版反爬太厉害,因此选择爬取手机端. 微博手机端地址:https://m.weibo.cn 1 需求 爬取李子柒微博中视频的评论信息 ...
- 百度贴吧界面html程序代码,python爬虫例题:爬取百度贴吧评论区图片和视频
百度贴吧是全球最大的中文交流平台,你是否跟我一样,有时候看到评论区的图片想下载呢?或者看到一段视频想进行下载呢? 今天,本期Python教程带大家通过搜索关键字来获取评论区的图片和视频. [二.项目目 ...
- 爬取b站视频评论用户信息!这些评论的才是大神!
最近马保国老师在b站挺火的,关于他的视频播放量很高,b站视频评论区都是人才说话好听,写个爬虫爬取一下b站评论区用户信息和评论内容. 一.准备工作 1.工具 (1)Chrome 谷歌浏览器 安装地址:h ...
- python3网络爬虫--爬取b站视频评论用户信息(附源码)
文章目录 一.准备工作 1.工具 二.思路 1.整体思路 2.爬虫思路 三.分析网页 1.分析网页加载方式 2.分析数据接口 3.获取oid 四.撰写爬虫 五.存储数据 六.总结 你爱我,我爱你,蜜雪 ...
- python爬取网易云音乐评论并进行可视化分析
2019独角兽企业重金招聘Python工程师标准>>> 前言 今天为大家一个爬取网易云音乐评论的Python案例,并用Python的第三方库来进行可视化分析,生成图表样式,可以清晰地 ...
- 中国女足绝地大逆转,爬取了微博评论区,评论很精彩
昨晚,女足16年后重夺亚洲杯,决赛落后两球,依然能保持对比赛的观察和思考,下半场从容调度人手,最后完成逆转. 打开微博一看,WC,微博推给我的第一条就是一篇瓜文. 这几天正好有的瓜,于是就爬了一下微博 ...
- 爬取了 36141 条评论数据,解读 9.5 分的《海王》是否值得一看
这是第一个python项目,之前看到了<爬取了 48048 条评论数据,解读 9.3 分的<毒液>是否值得一看?>这篇文章,一直想自己动手做一个,刚刚好前两天看了<海王& ...
- 简单的爬取B站视频评论
2019年12月20日15:14:09补充: 这篇博客为刚学爬虫的一个简单实践,主要使用到的为selenium模拟点击 补充说明的主要原因是有小伙伴问我评论提取的相关问题,这里统一回复一下 最简单的办 ...
最新文章
- Wiki动画回顾系列序目录
- LeetCode Best Time to Buy and Sell Stock with Cooldown(动态规划)
- sdwan支持的网络设备类型
- 淮海工学院linux实验报告三,作业三 实验报告
- 02基于python玩转人工智能最火框架之TensorFlow人工智能深度学习介绍
- 关于iOS里的做动画方法的差别与注意事项
- es中的一些知识点记录
- 软帝java培训实习日志,在软帝学习的第一个星期的小总结
- Excel度分秒转度--公式大解析
- 类似微信的即时通讯服务器,除了微信,还有这些常用即时通讯APP
- 【OS笔记 4】操作系统的组织结构(层次结构、微内核结构)虚拟机的概念
- 维生素D与肠道菌群的互作
- 详解去中心化代币发行机制IDO:七大平台的特性与现状 |链捕手
- E. Xenon's Attack on the Gangs,Codeforces Round #614 (Div. 2),树形dp
- java计算机毕业设计移动垃圾分类车管理平台源码+系统+mysql数据库+lw文档
- 【问题解决】samba添加用户和密码时报错 Failed to add entry for user
- 深入学习SpringMVC框架
- HTTP (RESTful) API 响应时间分析及SLA定义
- 解密openGauss DB4AI框架的内部机理
- 刷题_25:星际密码 and 数根
热门文章
- 腾讯企鹅号联合新榜发布内容创作版权保护行业报告
- methods的使用
- The import java.io cannot be resolved (类库无法解析的问题解决 )
- android手机闪退原因
- Tigress学习系列【1】(安装与排错)
- java arrays.sort原理_Arrays.sort()原理
- 技术分享 | 使用 sync_diff_inspector 对两个 MySQL 进行数据校验
- css边框角;table 合并单元格
- MT6739 PDAF移植
- 机械师F117毒药 评测怎么样