Python爬虫爬取微信朋友圈


Posted in Python onAugust 06, 2020

接下来,我们将实现微信朋友圈的爬取。
如果直接用 Charles 或 mitmproxy 来监听微信朋友圈的接口数据,这是无法实现爬取的,因为数据都是被加密的。而 Appium 不同,Appium 作为一个自动化测试工具可以直接模拟 App 的操作并可以获取当前所见的内容。所以只要 App 显示了内容,我们就可以用 Appium 抓取下来。

1. 本节目标

本节我们以 Android 平台为例,实现抓取微信朋友圈的动态信息。动态信息包括好友昵称、正文、发布日期。其中发布日期还需要进行转换,如日期显示为 1 小时前,则时间转换为今天,最后动态信息保存到 MongoDB。

2. 准备工作

请确保 PC 已经安装好 Appium、Android 开发环境和 Python 版本的 Appium API。Android 手机安装好微信 App、PyMongo 库,安装 MongoDB 并运行其服务,安装方法可以参考第 1 章。

3. 初始化

首先新建一个 Moments 类,进行一些初始化配置,如下所示:

PLATFORM = 'Android'
DEVICE_NAME = 'MI_NOTE_Pro'
APP_PACKAGE = 'com.tencent.mm'
APP_ACTIVITY = '.ui.LauncherUI'
DRIVER_SERVER = 'http://localhost:4723/wd/hub'
TIMEOUT = 300
MONGO_URL = 'localhost'
MONGO_DB = 'moments'
MONGO_COLLECTION = 'moments'
 
class Moments():
  def __init__(self):
    """初始化"""
    # 驱动配置
    self.desired_caps = {
      'platformName': PLATFORM,
      'deviceName': DEVICE_NAME,
      'appPackage': APP_PACKAGE,
      'appActivity': APP_ACTIVITY
    }
    self.driver = webdriver.Remote(DRIVER_SERVER, self.desired_caps)
    self.wait = WebDriverWait(self.driver, TIMEOUT)
    self.client = MongoClient(MONGO_URL)
    self.db = self.client[MONGO_DB]
    self.collection = self.db[MONGO_COLLECTION]

这里实现了一些初始化配置,如驱动的配置、延时等待配置、MongoDB 连接配置等。

4. 模拟登录

接下来要做的就是登录微信。点击登录按钮,输入用户名、密码,提交登录即可。实现样例如下所示:

def login(self):
  # 登录按钮
  login = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/cjk')))
  login.click()
  # 手机输入
  phone = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/h2')))
  phone.set_text(USERNAME)
  # 下一步
  next = self.wait.until(EC.element_to_be_clickable((By.ID, 'com.tencent.mm:id/adj')))
  next.click()
  # 密码
  password = self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@resource-id="com.tencent.mm:id/h2"][1]')))
  password.set_text(PASSWORD)
  # 提交
  submit = self.wait.until(EC.element_to_be_clickable((By.ID, 'com.tencent.mm:id/adj')))
  submit.click()

这里依次实现了一些点击和输入操作,思路比较简单。对于不同的平台和版本来说,流程可能不太一致,这里仅作参考。

登录完成之后,进入朋友圈的页面。选中朋友圈所在的选项卡,点击朋友圈按钮,即可进入朋友圈,代码实现如下所示:

def enter(self):
  # 选项卡
  tab = self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@resource-id="com.tencent.mm:id/bw3"][3]')))
  tab.click()
  # 朋友圈
  moments = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/atz')))
  moments.click()

抓取工作正式开始。

5. 抓取动态

我们知道朋友圈可以一直拖动、不断刷新,所以这里需要模拟一个无限拖动的操作,如下所示:

# 滑动点
FLICK_START_X = 300
FLICK_START_Y = 300
FLICK_DISTANCE = 700
 
def crawl(self):
  while True:
    # 上滑
    self.driver.swipe(FLICK_START_X, FLICK_START_Y + FLICK_DISTANCE, FLICK_START_X, FLICK_START_Y)

我们利用 swipe() 方法,传入起始和终止点实现拖动,加入无限循环实现无限拖动。

获取当前显示的朋友圈的每条状态对应的区块元素,遍历每个区块元素,再获取内部显示的用户名、正文和发布时间,代码实现如下所示:

# 当前页面显示的所有状态
items = self.wait.until(
  EC.presence_of_all_elements_located((By.XPATH, '//*[@resource-id="com.tencent.mm:id/cve"]//android.widget.FrameLayout')))
# 遍历每条状态
for item in items:
  try:
    # 昵称
    nickname = item.find_element_by_id('com.tencent.mm:id/aig').get_attribute('text')
    # 正文
    content = item.find_element_by_id('com.tencent.mm:id/cwm').get_attribute('text')
    # 日期
    date = item.find_element_by_id('com.tencent.mm:id/crh').get_attribute('text')
    # 处理日期
    date = self.processor.date(date)
    print(nickname, content, date)
    data = {
      'nickname': nickname,
      'content': content,
      'date': date,
    }  
  except NoSuchElementException:
    pass

这里遍历每条状态,再调用 find_element_by_id() 方法获取昵称、正文、发布日期对应的元素,然后通过 get_attribute() 方法获取内容。这样我们就成功获取到朋友圈的每条动态信息。

针对日期的处理,我们调用了一个 Processor 类的 date() 处理方法,该方法实现如下所示:

def date(self, datetime):
  """
  处理时间
  :param datetime: 原始时间
  :return: 处理后时间
  """
  if re.match('d + 分钟前 ', datetime):
    minute = re.match('(d+)', datetime).group(1)
    datetime = time.strftime('% Y-% m-% d', time.localtime(time.time() - float(minute) * 60))
  if re.match('d + 小时前 ', datetime):
    hour = re.match('(d+)', datetime).group(1)
    datetime = time.strftime('% Y-% m-% d', time.localtime(time.time() - float(hour) * 60 * 60))
  if re.match(' 昨天 ', datetime):
    datetime = time.strftime('% Y-% m-% d', time.localtime(time.time() - 24 * 60 * 60))
  if re.match('d + 天前 ', datetime):
    day = re.match('(d+)', datetime).group(1)
    datetime = time.strftime('% Y-% m-% d', time.localtime(time.time()) - float(day) * 24 * 60 * 60)
  return datetime

这个方法使用了正则匹配的方法来提取时间中的具体数值,再利用时间转换函数实现时间的转换。例如时间是 5 分钟前,这个方法先将 5 提取出来,用当前时间戳减去 300 即可得到发布时间的时间戳,然后再转化为标准时间即可。

最后调用 MongoDB 的 API 来实现爬取结果的存储。为了去除重复,这里调用了 update() 方法,实现如下所示:

self.collection.update({'nickname': nickname, 'content': content}, {'$set': data}, True)

首先根据昵称和正文来查询信息,如果信息不存在,则插入数据,否则更新数据。这个操作的关键点是第三个参数 True,此参数设置为 True,这可以实现存在即更新、不存在则插入的操作。

最后实现一个入口方法调用以上的几个方法。调用此方法即可开始爬取,代码实现如下所示:

def main(self):
  # 登录
  self.login()
  # 进入朋友圈
  self.enter()
  # 爬取
  self.crawl()

这样我们就完成了整个朋友圈的爬虫。代码运行之后,手机微信便会启动,并且可以成功进入到朋友圈然后一直不断执行拖动过程。控制台输出相应的爬取结果,结果被成功保存到 MongoDB 数据库中。

6. 结果查看

我们到 MongoDB 中查看爬取结果,如图所示。

Python爬虫爬取微信朋友圈

可以看到朋友圈的数据就成功保存到了数据库。

7. 本节代码

8. 结语

以上内容是利用 Appium 爬取微信朋友圈的过程。利用 Appium,我们可以做到 App 的可见即可爬,也可以实现自动化驱动和数据爬取。但是实际运行之后,Appium 的解析比较烦琐,而且容易发生重复和中断。如果我们可以用前文所说的 mitmdump 来监听 App 数据实时处理,而 Appium 只负责自动化驱动,它们各负其责,那么整个爬取效率和解析效率就会高很多。

以上就是Python爬虫爬取微信朋友圈的详细内容,更多关于Python爬取微信朋友圈的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
批处理与python代码混合编程的方法
May 19 Python
python利用有道翻译实现"语言翻译器"的功能实例
Nov 14 Python
利用 python 对目录下的文件进行过滤删除
Dec 27 Python
Python数据分析之双色球基于线性回归算法预测下期中奖结果示例
Feb 08 Python
Python中__slots__属性介绍与基本使用方法
Sep 05 Python
Python3.6实现带有简单界面的有道翻译小程序
Apr 16 Python
Python 列表的清空方式
Jan 13 Python
Python解析多帧dicom数据详解
Jan 13 Python
jupyter notebook 多环境conda kernel配置方式
Apr 10 Python
Python3.7安装PyQt5 运行配置Pycharm的详细教程
Oct 15 Python
Python修改DBF文件指定列
Dec 19 Python
Python中文分词库jieba(结巴分词)详细使用介绍
Apr 07 Python
Python变量及数据类型用法原理汇总
Aug 06 #Python
基于logstash实现日志文件同步elasticsearch
Aug 06 #Python
如何解决pycharm调试报错的问题
Aug 06 #Python
Python用来做Web开发的优势有哪些
Aug 05 #Python
Python结合Window计划任务监测邮件的示例代码
Aug 05 #Python
python爬虫使用requests发送post请求示例详解
Aug 05 #Python
8种常用的Python工具
Aug 05 #Python
You might like
收集的DedeCMS一些使用经验
2007/03/17 PHP
PHP下通过file_get_contents的代理使用方法
2011/02/16 PHP
laravel框架邮箱认证实现方法详解
2019/11/22 PHP
jquery 输入框数字限制插件
2009/11/10 Javascript
jQuery之排序组件的深入解析
2013/06/19 Javascript
JavaScript中的object转换成number或string规则介绍
2014/12/31 Javascript
js函数与php函数的区别实例浅析
2015/01/12 Javascript
小心!AngularJS结合RequireJS做文件合并压缩的那些坑
2016/01/09 Javascript
运用js教你轻松制作html音乐播放器
2020/04/17 Javascript
node.js入门学习之url模块
2017/02/25 Javascript
浅谈webpack编译vue项目生成的代码探索
2017/12/11 Javascript
纯JS实现的读取excel文件内容功能示例【支持所有浏览器】
2018/06/23 Javascript
vue+element+Java实现批量删除功能
2019/04/08 Javascript
JS实现的检验身份证格式并输出出生日期,年龄,性别,出生地示例
2019/05/17 Javascript
JS中的变量作用域(console版)
2020/07/18 Javascript
Vue使用轮询定时发送请求代码
2020/08/10 Javascript
用vue设计一个日历表
2020/12/03 Vue.js
python读写ini文件示例(python读写文件)
2014/03/25 Python
深入理解python中的select模块
2017/04/23 Python
Python中标准库OS的常用方法总结大全
2017/07/19 Python
python cumsum函数的具体使用
2019/07/29 Python
Python进程的通信Queue、Pipe实例分析
2020/03/30 Python
Tensorflow--取tensorf指定列的操作方式
2020/06/30 Python
详解vscode实现远程linux服务器上Python开发
2020/11/10 Python
CSS3实现跳动的动画效果
2016/09/12 HTML / CSS
使用HTML5 Canvas为图片填充颜色和纹理的教程
2016/03/21 HTML / CSS
基督教卡片、励志礼品、家居装饰等:DaySpring
2018/10/12 全球购物
高中自我评价范文
2014/01/27 职场文书
服务型党组织建设典型材料
2014/05/07 职场文书
员工保密承诺书
2014/05/28 职场文书
城市轨道交通工程职业生涯规划书范文
2014/09/16 职场文书
领导干部贪图享乐整改措施
2014/09/21 职场文书
2015年打非治违工作总结
2015/04/02 职场文书
《角的初步认识》教学反思
2016/02/17 职场文书
Python机器学习之基于Pytorch实现猫狗分类
2021/06/08 Python
java实现自定义时钟并实现走时功能
2022/06/21 Java/Android