环境
1.MacBook
2.小米手机(已root)-红米note4x
3.pycharm
整体思路
-
基于Airtest编写自动化脚本,比如自动下拉列表
-
把Airtest代码copy到pycharm运行
-
安装Mitmproxy,编写拦截脚本并运行,实现爬取接口返回数据
实践
-
基于Airtest编写自动化脚本
Airtest 是一个跨平台的、 **基于图像识别 **的
UI自动化测试框架,适用于游戏和App,支持平台有Windows、Android 和 IOS,主要编写语言为 python。Airtest基本[Api]使用:
- 获取元素:
ls = poco(name="com.xingin.xhs:id/aj8") 经过name获取ls = poco(text=item.get_text()) 经过textpoco("android.widget.LinearLayout").offspring("com.xingin.xhs:id/ak6") 经过目录树
- 点击元素:
x.click() - 获取文本:
x.get_text() - 滑动屏幕:
swipe([0.5, 0.8], [0.5, 0.7]) 从一个点到另外一个点 - 是否存在:
x.exist()
- 获取元素:
-
基于Mitmproxy拦截请求响应体
mitmproxy是一个支持HTTP和HTTPS的抓包程序,相似Fiddler、Charles的功能,只不过它经过控制台的形式操做;使用 mitmproxy 最主要是使用它的一个组件 mitmdump ,它能够经过python脚本处理响应内容,相似于Fiddler的界面抓包,可是咱们能够更加方便地拿到响应数据
mitmproxy基本命令
#安装mitmproxy pip3 install mitmproxy #http.HTTPFlow 实例 flow #flow.request.headers #获取所有头信息,包含Host、User-Agent、Content-type等字段 #flow.request.url #完整的请求地址,包含域名及请求参数,但是不包含放在body里面的请求参数 #flow.request.pretty_url #同flow.request.url目前没看出什么差别 #flow.request.host #域名 #flow.request.method #请求方式。POST、GET等 #flow.request.scheme #什么请求 ,如https #flow.request.path # 请求的路径,url除域名之外的内容 #flow.request.get_text() #请求中body内容,有一些http会把请求参数放在body里面,那么可通过此方法获取,返回字典类型 #flow.request.query #返回MultiDictView类型的数据,url直接带的键值参数 #flow.request.get_content()#bytes,结果如flow.request.get_text() #flow.request.raw_content #bytes,结果如flow.request.get_content() #flow.request.urlencoded_form #MultiDictView,content-type:application/x-www-form-urlencoded时的请求参数,不包含url直接带的键值参数 #flow.request.multipart_form #MultiDictView,content-type:multipart/form-data #以上均为获取request信息的一些常用方法,对于response,同理 #flow.response.status_code #状态码 #flow.response.text#返回内容,已解码 #flow.response.content #返回内容,二进制 #flow.response.setText()#修改返回内容,不需要转码 #以上为不完全列举#爬取小红书列表脚本(xhs.py)
#xhs.py from mitmproxy import ctx import json import csv import urllib.parse try: # 所有的请求都会经过request def request(flow): print("flow.request.url==========", flow.request.url) #搜索 if "https://edith.xiaohongshu.com/api/sns/v10/search/notes" in flow.request.url: d = {} test = urllib.parse.parse_qs(urllib.parse.urlparse(flow.request.url).query) print("aaatest=",str(test["keyword"][0])) # 所有的请求都会经过response def response(flow): if "https://edith.xiaohongshu.com/api/sns/v10/search/notes" in flow.request.url: # d = {"text": str(flow.response.text)} # content = json.dumps(d) keywordStr = urllib.parse.parse_qs(urllib.parse.urlparse(flow.request.url).query) keyword = keywordStr["keyword"][0] content = json.loads(flow.response.text) f = open('小红书.csv', 'a+', encoding='utf-8') # a+表示追加 csv_writer = csv.writer(f) csv_writer.writerow(["id", "类型", "标题", "摘要", "点赞", "用户名", "用户头像", "用户id", "发布时间", "搜索关键词"]) for i in range(len(content["data"]["items"])): id = content["data"]["items"][i]["note"]["id"] type = content["data"]["items"][i]["note"]["type"] desc = content["data"]["items"][i]["note"]["desc"] title = content["data"]["items"][i]["note"]["title"] img_user = content["data"]["items"][i]["note"]["user"]["images"] like = content["data"]["items"][i]["note"]["liked_count"] user = content["data"]["items"][i]["note"]["user"]["nickname"] user_id = content["data"]["items"][i]["note"]["user"]["userid"] time = content["data"]["items"][i]["note"]["timestamp"] note_url = "https://www.xiaohongshu.com/discovery/item/" + str(id) # star1 = get_star_comment(note_url)[0] # comment1 = get_star_comment(note_url)[1] # t1="id: {},标题:{},喜欢:{},用户名:{},用户头像:{}, 用户id: {}, 发布时间:{}, 收藏数:{}, 评论数: {}".format(id,title,like,user,img_user,user_id,time,star1, comment1)+"\n" # print(t1) csv_writer.writerow([id, type, title, desc, like, user, img_user, user_id, time, keyword]) f.close() except: pass -
在PyCharm运行脚本
Airtest与Pycharm不能同时运行
- 运行run_xhs.py脚本,可方便debug(xhs.py)
import sys import os from mitmproxy.tools.main import mitmdump sys.path.append(os.path.dirname(os.path.abspath(__file__))) print(os.path.dirname(os.path.abspath(__file__))) mitmdump(['-s', 'xhs.py','-p','8085'])- PyCharm安装pocoui
pip install pocoui- 编写自动下拉脚本(auto_swipe.py),先在Airtest写好,然后再copy到pycharm
# -*- encoding=utf8 -*- __author__ = "Nero" from airtest.core.api import * import random auto_setup(__file__) import logging from poco.drivers.android.uiautomation import AndroidUiautomationPoco poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False) logger = logging.getLogger("airtest") logger.setLevel(logging.ERROR) # poco(text="小红书").click() # sleep(10.0) # 搜索框 poco(name="com.xingin.xhs:id/c2b").click() # 搜索关键字 poco(name="com.xingin.xhs:id/b6i").set_text("护肤") # 点击搜索 poco(name="com.xingin.xhs:id/b6m").click() # biji_list[0].click() swipe = True total = 0 while swipe: # 滑动的速率,(0,1) duration = random.random() # 提高容错:判断当前页面是否在loading,措施:向上滑再恢复下滑 isLoading = poco(name="com.xingin.xhs:id/at_").exists() print("isLoading=", isLoading) while isLoading: sleep(5.0) poco.swipe([0.5, 0.2], [0.5, 0.8], duration=duration) poco.swipe([0.5, 0.2], [0.5, 0.8], duration=duration) isLoading = poco(name="com.xingin.xhs:id/at_").exists() # 向下滑动 poco.swipe([0.5, 0.8], [0.5, 0.2], duration=duration) sleep(1) # 判断是否已到底 isLast = poco(name="com.xingin.xhs:id/aqi").exists() if isLast: if (poco(name="com.xingin.xhs:id/aqi").get_text() == '无更多内容'): swipe = False print("total=", total)4.最后先执行run_xhs.py,再执行auto_swipe.py即可