简单实现
0 前言
爬取朋友圈的办法还是有很多的,今天我来介绍一下我最近发现的一个办法。
需要的是一台安卓手机,一台 Windows 电脑(ios + Mac 也可以)。
AirtestIDE 是网易出的跨平台的 UI 自动化编辑器,可以用来做自动化测试和爬虫。
这里用来爬取朋友圈的信息,下面把 AirtestIDE 简称为 IDE。
官网链接:http://airtest.netease.com 官方文档:http://airtest.netease.com/docs/cn
1 前置准备
下载回来解压之后,找到 AirtestIDE.exe 双击打开,想注册登录可以注册登录,不想的话就 Skip 跳过。
进来之后是这样的,
左上角的文件里面可以新建脚本,一般用户创建个 Airtest 的就行,能力高的纯 Python 也没毛病。
IDE 会自动创建好脚本
确保安卓手机已经打开开发者模式,且允许 USB 调试,而且已经用 USB 连接上电脑。
界面右上角的设备窗里面找到 移动设备连接,点击刷新 ADB ,设备出来之后点击 connect 进行连接。
如果能在 AirtestIDE 里面实时看到你的安卓手机,那就是可以了。
如果出现问题,请一步一步排查,看一下是不是少操作了一步,也可以看官方文档。
http://airtest.netease.com/docs/cn/2_device_connection/1_android_phone_connection.html 到这里,已经是连接上手机了,可以进行下一步了。
2 代码准备
找到 Poco 辅助窗,然后点击一下 Stop ,在下列框中选择 Android。
接着在脚本里面有一个提示,点击 Yes 就行 IDE 会自动导入需要的东西。
然后在 UI 渲染树 那里能看到手机当前页面的 UI 树。
不同版本的微信可能会有所不同,我使用的微信版本是 7.0.7。这里主要讲的是思路,代码是辅助。
前面 IDE 自动生成的代码就略过,只讲一下需要写的代码。
start_app('com.tencent.mm') # 启动微信
poco(text="发现").click() # 点击发现
# poco("com.tencent.mm:id/bu").offspring("com.tencent.mm:id/bv").child("android.widget.LinearLayout").child("android.widget.RelativeLayout")[2].offspring("com.tencent.mm:id/djv").click()
poco(text="朋友圈").click() # 点击朋友圈
首先是启动微信,这里非常简单 start_app(‘com.tencent.mm’) 就可以了,com.tencent.mm 是微信的包名,如果换一个应用就需要换包名。
poco(text=”发现”).click() 是找到 text 属性为 发现 的 UI,然后点击它,.click()就是点击,朋友圈那个同理。
我注释掉了一句代码,那句也是点击 发现 的,但是比较长,所以注释掉,然后使用短的那一句代码。
这里必须说一下这行代码是怎么出来的。
在 Poco 辅助窗那点击下图中圈中的那个图标,Poco Inspector,然后到手机界面中移动到想要点击的那个 UI ,然后 UI 树会自动展开。
去 UI 树那双击想要点击的 UI ,代码会自动添加,然后加上 .click()
我知道文字表述得不够清晰,所以有动图。
当然,可以选择录制脚本
点击这个之后,去手机页面进行点击,IDE 会自动把语句生成。
所以目前是已经打开微信,点击了发现,进入了朋友圈。
while True:
result_obj = poco("com.tencent.mm:id/f3l")
for result in result_obj:
try:
name = result.offspring("com.tencent.mm:id/bag").get_text()
context = result.offspring("com.tencent.mm:id/f3p").get_text()
print(name,context)
print()
except:
pass
dev = device() # 获取当前手机设备
dev.minitouch.swipe_along([[817, 2170],[506, 32]])
sleep(2.5) # 暂停 2.5 秒
看下图就可以知道,一条朋友圈就是在一个 name 为 com.tencent.mm:id/f3l 的FrameLayout 里面的。
poco(“com.tencent.mm:id/f3l”) 就是获取界面上能看到的朋友圈。
result_obj = poco(“com.tencent.mm:id/f3l”) 是把界面上能看到的朋友圈全部获取然后赋值到 result_obj ,待会对 result_obj 进行 for 循环,遍历出需要的内容来。
由下图可以看出,com.tencent.mm:id/bag 是 昵称/备注, com.tencent.mm:id/f3p 是文字内容。
name = result.offspring(“com.tencent.mm:id/bag”).get_text() 的意思就是把某一条朋友圈的昵称提取出来,赋值给 name,context 同理。
因为很有可能会出现问题,所以我 try except 了一下。
dev = device() 是获取当前手机设备,因为遍历完了当前的这些就需要上滑加载更多。
dev.minitouch.swipe_along([[817, 2170],[506, 32]]) 就是上滑。[817, 2170] 和 [506, 32] 就是坐标,dev.minitouch.swipe_along([A,B])的意思就是从 A 坐标 滑动到 B 坐标。
左上角的选项那里有个设置,设置里面有个实时坐标显示,勾选了之后,鼠标移动到手机界面就能看到实时坐标。
相对坐标也可以使用勾选,按道理应该在适配上更好一点。
效果就是这样
把这些代码放在 while True: 里面,这样就能一直运行下去了。
3 完整代码
下面这个的代码只是使用 IDE 进行输出,不需要使用 Python 环境;
# -*- encoding=utf8 -*-
__author__ = "ASUS"
from airtest.core.api import *
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)
start_app('com.tencent.mm') # 启动微信
sleep(6.6)
poco(text="发现").click() # 点击发现
poco(text="朋友圈").click() # 点击朋友圈
while True:
result_obj = poco("com.tencent.mm:id/f3l")
for result in result_obj:
try:
name = result.offspring("com.tencent.mm:id/bag").get_text()
context = result.offspring("com.tencent.mm:id/f3p").get_text()
print(name,context)
print()
except:
pass
dev = device() # 获取当前手机设备
dev.minitouch.swipe_along([[817, 2170],[506, 32]]) # 向上滑动
sleep(2.5) # 暂停 2.5 秒
如果是要保存的话,那就得需要使用 Python 了。保存到 csv 文件的 python 代码就在下面。
建议是使用 IDE 来创建,这样会自动填写连接手机的代码。
“Android://127.0.0.1:5037/d918c48a” 这里 d918c48a 就是下图显示的这个,不同手机是不一样的。(如果知道 adb 的话,直接 cmd 里面 adb devices 查看)
# -*- encoding=utf8 -*-
__author__ = "ASUS"
import csv
from airtest.core.api import *
from airtest.cli.parser import cli_setup
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)
if not cli_setup():
auto_setup(__file__, logdir=True, devices=[
"Android://127.0.0.1:5037/d918c48a",
])
# generate html report
# from airtest.report.report import simple_report
# simple_report(__file__, logpath=True)# script content
start_app('com.tencent.mm') # 启动微信
sleep(6.6)
poco(text="发现").click() # 点击发现
poco(text="朋友圈").click() # 点击进入朋友圈
with open('pyq.csv', "w", newline="", encoding="utf-8-sig") as f:
csv_write = csv.writer(f)
csv_head = ["昵称", "文本内容"]
csv_write.writerow(csv_head)
while True:
result_obj = poco("com.tencent.mm:id/f3l")
out = open("pyq.csv", "a+", newline="", encoding="utf-8-sig")
csv_writer = csv.writer(out, dialect="excel")
for result in result_obj:
try:
name = result.offspring("com.tencent.mm:id/bag").get_text()
context = result.offspring("com.tencent.mm:id/f3p").get_text()
print(name, context)
row = [name, context]
csv_writer.writerow(row)
print()
except:
pass
out.close()
dev = device() # 获取当前手机设备
dev.minitouch.swipe_along([[817, 2170], [506, 32]]) # 向上滑动
sleep(2.5)
4 相关说明
AirtestIDE 是可以只运行部分代码的
稍微做一下修改的话,那么就不是爬取整个朋友圈了,而是可以单独爬取一个人的朋友圈。
这样爬取下来的只是昵称 + 文字,如果想爬取更多,可以试试 hook 或者 mitmproxy 抓包,如果有更好的方式,欢迎大佬留言