美文网首页
2020移动端python爬虫实战笔记

2020移动端python爬虫实战笔记

作者: Mr培 | 来源:发表于2020-08-29 11:09 被阅读0次

Uiautomator2

  • 支持环境

Androidhg4 4.4+
Python 3.6+ ( 3.8暂不支持)

课程开发环境

开发环境: Windows 10
运行环境: ubuntu18.04 (提供虚拟机文件)
虚拟机: VMware⑧Workstation 15 Pro (提供软件安装包)
SSH : SecureCrt Version 7.0.0 (提供绿色软件安装包)
IDE : PyCharm 2019.3.2 (Professional Edition) ( 提供软件安装包)
安卓模拟器:夜神模拟器V6.6.0 (提供软件安装包)
Python版本: python3.6.9 ( 提供安装包)

开发环境注意事项

不要使用vitualbox虚拟机 与安卓模拟器冲突

执行流程
[图片上传失败...(image-278648-1598670535406)]

① 在移动设备上安装atx-agent(守护进程),随后atx-agent启动uiautomator2服
务(默认7912端口)进行监听
② 在PC.上编写测试脚本并执行(相当于发送HTTP请求到移动设备的server端)
③ 移动设备通过WIFI或USB接收到PC.上发来的HTTP请求,执行制定的操作

环境搭建
  1. 安装 virtualenv
  1. 创建一个虚拟的python环境
  • python3 -m virtualenv venv

进入虚拟环境
- source venv/bin/activate
查看安装的包(依赖)
- pip freeze
配置PyCharm的python环境

adb

  1. Android调试桥(adb)

adb client :命令行程序"adb" 用于从shel或脚本中运行adb命令。
adb server : ADB Server是运行在PC上的一个后台进程。
adbd :程序"adbd" 作为一个后台进程在Android设备或模拟器系统中运行。

  1. adb能用来做什么

安装卸载apk
移动设备和PC之间拷贝文件
查看设备上安装的应用信息
文件管理
各种刷机工具
各种手机root工具

  1. mac环境adb安装教程

查看连接的移动端设备

  • adb devices

给移动设备安装apk应用

  • adb install xxx.apk

查看移动设备apk包名

  • adb shell pm list packages

卸载移动设备apk应用

  • adb uninstall com.xxx.xxxx
Uiautomator2安装

在python虚拟环境下

安装依赖

  • pip install uiautomator2 -i https://pypi.douban.com/simple

    重要注意⚠️

  • python -m uiautomator2 init

    安装u2包:
    uiautomator-server :就是谷歌原生的uiautomator
    atx-agent : uiautomator的守护进程
    atx-agent增加远程控制的功能,依赖minicap和minitouch这两个工具
    ⚠️python -m uiautomator2 init报错Can't connect to HTTPS URL because the SSL module is not available

⚠️pyenv重新安装python

u2连接移动设备的三种方式
import uiautomator2 as u2
#通过手机WIFI来连接,需要查看手机的IP地址
d = u2.connect_wifi("192.168.0.130")
print(d.info)
import uiautomator2 as u2
#通过手机的序列号来连接
d = u2.connect_usb("4bf05af7")
print(d.info)
import uiautomator2 as u2
#通过adb wifi也就是 adb tcpip模式,注意不要丢掉端口号
d = u2.connect_adb_wifi("192.168.1.7:5555")
#device_info可以获取详细的设备信息
print(d.device_info)
import uiautomator2 as u2
import time
#启动手机上的app,通过aapt工具来获取包名
#appt获取包名的时候,在aapt dump badging xxx.apk,获取到的是包名
d.app_start("com.ss.android.ugc.aweme")
#运行五秒
time.sleep(5)
#停止抖音app
d.app_stop("com.ss.android.ugc.aweme" )
u2自动化工具基本操作
import uiautomator2 as u2
import time
d = u2.connect_wifi("192.168.0.130")
# 查看设备信息
print(d.service("uiautomator").running())
d.service("uiautomator").start()
time.sleep(2)
print(d.service("uiautomator").running())
# 停止服务
d.service("uiautomator").stop()
time.sleep(2)
print(d.service("uiautomator").running())
# 查看atx-agent运行状态,如果atx-agent真的停止了,我们可以通过connect来唤醒atx-agent服务
print(d.agent_alive)
# 查看设备的分辨率
print(d.window_size())
# 查看获取到的wifi地址
print(d.wlan_ip)
import uiautomator2 as u2
# 通过wifi进行连接
d = u2.connect_wifi("192.168.0.130")
# 通过app_install 方法安装 apk,url=“xxx.apk”
d.app_install(url="")

# 启动app
d.app_start(package_name="cn.com.open.mooc")
# 获取当前前台运行的app的信息
print(d.app_current())
# d.app_stop("cn.com.open.mooc")
# 获取app的详细信息
print(d.app_info(pkg_name=""))
# 清楚app缓存
d.app_clear("cn.com.open.mooc")
# 卸载app
d.app_uninstall("cn.com.open.mooc")
# 获取所有app列表
print(d.app_list())
# 获取所有正在运行的app列表
prin(d.app_list_running())
# 停止所有app
d.app_stop_all()
# 卸载所有第三方app
d.app_uninstall_all()
activity和控件,weditor工具的安装
  • 安装weditor

    pip install weditor -j https:lpypi.tuna.tsinghua.edu.cn/simplel

weditor启动和介绍

查看版本

  • pip freeze | grep weditor

查看是否启动

  • weditor

查看atx-agent是否启动

  • adb shell
  • ps | grep atx-agent
UiSelector和控件定位介绍

UiSelector代表一种搜索标准,可以在当前展示界面上查询和获取特
定元素的句柄

# coding: utf-8
import uiautomator2 as u2
d = u2. connect_ usb("4bf05af7")
# 可以通过aapt这个工具来获取包名,是获取的apk的包名,设置这个app的apk
# 包名通过weditor来获取,package:com.android.settings
# 启动设置app
d.app_start(package_name="com.android.settings")

#全文本匹配,点击
d(text="其他无线连接").click()
#文本包含
d(textContains="无线").click()
#传入正则表达式
d(textMatches=".{2}无线.{2}").click()
d(textStartsWith="其他无").c1ick()

#className选取方式
d(className="android.widget.TextView")[4].click()
#d(className="android.widget.TextView",instance=4).click()
d(classNameMatches="android\.widget\.\w{8}",text="蓝牙").click()

Text文本选取方式

  • text全文本匹配
  • textContains文本包含
  • textMatches正则表达式
  • textStartsWith起始文本

className选取方式

  • className className匹配
  • classNameMatches className正则表达式匹配

resourceld资源ID选取方式

  • resourceld全资源ID匹配
  • resourceldMatches正则表达式匹配
import uiautomator2 as u2
d = u2.connect_usb("4bf05af7")
# 通过资源ID来定位控件,通过索引来进行限定
# 可以选择多个控件,默认选择的是第一-个控件
d(resourceId="android:id/title")[2].click()
# 通过实例来进行查找,值和索引值是一样的
d(resourceId="android:id/title",instance=2).click()
# 物通过多个条件来进行限定
d(resourceId="android:id/title",text="蓝牙").click()
#通过正则表达式的方法来获取资源ID,进行控件的定团
d(resourceIdMatches="android:id\/\w{5}",text="蓝牙").click()

#逋辻className来狹取控件定位的吋候,需要注意层級夫系
# d(className="android.widget.TextView")[4].cLick()
# d(className="android.widget.TextView",instance=4).click()
# d(cLassNameMatches= "android\.widget\.\w[8]",text="蓝牙").cLick()
#这里是链式定位方式
# d(className="adroid.widget.ListView").child(text="蓝牙").cLick()
d(className="android.widget.ListView").child_by_text("蓝牙",resourceId="android:id/title").click()

#完全的链式定位方法,代码非常的冗长,我们是不建议的
d(className="android.widget.ListView").child(resourceId="oppo:id/oppo_ preference")[2].child(resourceId="android:id/title").click()
# 这种方法多次依据,也不建议
d(resourceId="oppo:id/oppo_preference").sibling(resourceId= "oppo:id/oppo_preference“).sibling(resourceId="oppo:id/oppo_ preference",instance=2).click()

坐标定位方式

import uiautomator2 as u2
d = u2.connect_usb("4bf05af7")
d.app_start("com.android.settings")
# 这里可以通过坐标点来进行控件的定位
# 我们可以选用实际的坐标点,也可以通过百分比来进行定位
d.click(0.168,0.341)
import uiautomator2 as u2
d = u2.connect_usb("4bfØ5af7")
d.app_start("com.android.settings")
# 控件不存在,我们该怎么办
# d(text="蓝牙").click(timeout=5)
# click_exists如果控件存在就点,如果控件不存在就返回,在timeout时间之内
d(text="蓝牙1").click_exists(timeout=5)
# 在操作之前,通过exists属性判断控件是否存在
# print(d(text="蓝牙1").exists)
# print(d(text="蓝牙1").exists(timeout=5))
#print(d(resourceId="android:id/list").child(resourceId="oppo:id/oppo_ preference").count)
for view in d(resourceId="android:id/list").child(resourceId="oppo:id/oppo_ preference")
    print(view.indo)
通过U2实现移动设备九宫格解锁
import uiautomator2 as u2
d = u2.connect_usb("4bfØ5af7")
# 滑动解锁操作
# 息屏
# d.screen_off()
# 点亮屏幕
#d.screen_on()
# 解锁
#d.unlock()
# 获取屏幕状态
#print(d.info.get("screenOn"))
# home键
#d.press("home")
# 返回键
#d.press("back")
# 向左滑
# d.swipe_ext("left")
# 向右滑
# d.swipe_ext("right")

# 滑动解锁
#swipe_points
# 先解锁调出九宫格界面
d.unlock()
# 在 position 里面拿到坐标
# (0.224,0.393)
# (0.493,0.395)
# (0.781,0.396)
# (0.501,0.551)
# (0.218,0.703)
# (0.773,0.703)
# duration=0.2 是0.2秒
d.swipe_points(points=[
 (0.224,0.393),
 (0.493,0.395),
 (0.781,0.396),
 (0.501,0.551),
 (0.218,0.703),
 (0.773,0.703)
],duration=0.2)
xpath定位方式

Xpath常用规则:
/ 从当前节点选取直接子节点
// 从当前节点选取子孙节点
. 选取当前节点
.. 选取当前节点的父节点
@ 选取属性

import uiautomator2 as u2

d = u2.connect_usb("4bfØ5af7")
# 下载当前页面的源代码文件
with open("phone.file", 'w',encoding='utf-8') as f:
    # 通过这个方法来获取到控件的源代码文件
    f.write(d.dump_hierarchy())
  • XPath Helper 游览器扩展插件安装(科学上网安装)

//li[@class='other_item']/a/text())
//li[@class='item-3']//text()
//li[@class='item-3']/a/@href

  • XPath 规则获取 WEditor中XPath属性直接获取

1、文字属性定位
2、姿源ID属性定位
3、className属性定位
4、鍵式凋用美系定位
5、坐祢定位
6、xpath定位

实现自动化登录考研帮app并滑动资讯信息
import uiautomator2 as u2

class HandleMeituan(object):
    def __init__(self, serial="4bfØ5af7"):
        # 当前是通过usb的方法来连接移动设备的
        self.d = u2.connect_usb(serial=serial)
        self.size = self.get_windowsize()
        self.hand1e_watcher()
        
    def hand1e_watcher(self):
        “”"定义一个监控器“”“
        #监控器会单独的起一个线程
        #用户隐私协议
        self.d.watcher.when('//*[@resource-id="com.tal.kaoyan:id/tip_commit"]').c1ick()
        #广告
        self.d.watcher.when('//*[@resource-id="com.tal.kaoyan:id/tv_skip"]').c1ick()
        #监控器写好之后,要通过start方法来启动
        self.d.watcher.start()
        
    def get_windowsize(self) :
        """获取手机屏幕的大小"""
        return self.d.window_size()

    def close_app(self):
        #监控器关闭
        self.d.watcher.stop()
        #停止考研帮app
        self.d.app_stop("com.tal.kaoyan")
        #清理缓存
        self.d.app_clear("com.tal.kaoyan")

    def handle_meituan_app(self):
        """启动美团app,并实现自动化操作"""
        #aapt这个工具 或者 通过weditor 获取 package_name
        self.d.app_start(package_name="com.tal.kaoyan")
        # 在点击之前需要判断是否有这个控件
        self.d(text="密码登录").click_exists(timeout=10)
        # 通辻找到相美控件之后文本控件,set_text这个方法来輸入文字                                             self.d(resourceId="com.tal.kaoyan:id/login_email_edittext").set_text("450120127@qq.com")
        #输入密码
        self.d(resourceId='com.tal.kaoyan:id/login_password_edittext").set_text("123456")
        # self.d(resourceId"com.tal.kaoyan:id/login_login_btn").click()
        self.d(text="登录").click()
        #在10秒钟如果这个界面启动了
        if self.d.wait_activity("com.tal.kaoyan.ui.activity.HomeTabActivity",timeout=10):
            self.d(text="研迅").click_exists(timeout=10)
            #获取到屏幕的中心点,x轴
            #在获取到y轴远方点,获取到y轴近点
            x1 = int(self.size[0] * 0.5)
            y1 = int(self.size[1] * 0.9)
            y2 = int(self.size[1] * 0.15)
            while True:
                # get toast,是安卓系统系统的一个信息提示操作
                if self.d.toast.get_message(e) == "内容已经全部加载完了":
                    self.close_app()
                    return
                # 开始滑动研迅内容模块
                self.d.swipe(x1,y1,x1,y2)
                
if __name__== '__main__':
    k = HandleMeituan()
    k.handle_meituan_app()
u2自动化工具基本操作
import uiautomator2 as u2

# 通过wifi进行连接
d = u2.connect_wifi("192.168.1.8")
# 通辻app_install方法安装apk,url="xxx.apk"
d.app_install(url="="http:l/file.mukewang.com/apk/app/115/imooc7.3.41010.apk")
# 启动app
d.app_start(package_name="cn.com.open.mooc")
# 获取当前前台运行的app的信息
print(d.app_current())
d.app_stop("cn.com.open.mooc")
# 获取app详细信息
print(d.app_info(package_name="cn.com.open.mooc"))
# 清除app缓存
#尤其是我们后面要进行的视频数据抓取,会产生-定的缓存
d.app_clear("cn.com.open.mooc")
d.app_uninstall("cn.com.open.mooc")
#获取所有app列表
print(d.app_list())
#获取所有正在运行的app的列表
print(d.app_list_running())
#停止所有app
d.app_stop_a11()
#卸载所有app,卸载所有第三方app,u2项且包不会卸载'pm','list','packages','-3'
d.app_uninstall_a11()
fiddler抓包工具,file&edit功能使用
mitmproxy,mitmdump
from mitmproxy import ctx
# 必须这么写
def request(flowl):
    # print(flow.request.headers)
    ctx.log.info(str(flow.request.headers))
    ctx.log.warn(str(flow.request.headers))
    ctx.log.error(str(flow.request.headers))
    ctx.log.error(str(flow.request.url))
    ctx.log.error(str(flow.request.host))
    ctx.log.error(str(f1ow.request.method))
    ctx.log.error(str(f1ow.request.path))
    
def response(flow):
    ctx.log.error(str(flow.response.status_code))
    ctx.log.error(str(flow.response.text))

实战

创建项目
import uiautomator2 as u2
import time

class Douyin(object):
    #在__init__方法里面達接没各
    def__init__(self, serial="4bf05af7"):
        self.d = u2.connect_usb(serialeserial)
        self.start_app()
        self.handle_watcher()
        self.size = self.get_windowsize()
        #是用来获取一个初始时间
        self.t0 = time.perf_counter()
        
    def start_ app(self):
        """后劫app"""
        self.d.app_start(package_name="com.ss.android.ugc.aweme")
        
    def stop_app(self):
        """app退出逻辑"""
        # 先关闭监视器
        self.d.watcher.stop()
        self.d.app_stop("com.ss.android.ugc.aweme")
        self.d.app_clear("com.ss.android.ugc.aweme")
        
    def stop_time(self):
        """停止时间"""
        # 时间是秒
        if time.perf_counter() - self.tØ > 20:
            return True
        
    def handle_watcher(self):
        """监视器"""
        # 通知权限
        self.d.watcher.when('//*[@resource-id="com.ss.android.ugc.aweme:id/a4r"]').click()
        # 发现滑动查看更多
        self.d.watcher.when('//*[@text="滑动查看更多"]').click()
        # 添加一个监控器
        self.d.watcher.when('//*[@text="快熟进入TA的个人中心"]').click()
        # 监控器写好之后,一定要记得启动
        self.d.watcher.start(interval=1)
        
    def get_windowsize(self):
        # 获取窗口大小
        return self.d.windowsize()

    def swipe_douyin(self):
        “““滑动抖音视频和点击视频发布者头像的操作”””
        # 来判断是否正常的进入到了视频页面
        # 网络情况不好也包含在内了
        if self.d(resourceId="com.ss.android.ugc.aweme:id/yy", text="我").exists(timeout=20):
            while True:
                # 到规定的时间停生循环
                if self.stop_time():
                    self.stop_app()
                    return
                # 查看是不是正常的发布者
                if self.d(resourceId="com.ss.android.ugc.aweme:id/uØ").exists:
                    #是正常的发布者,点击头像
                    self.d(resourceId="com.ss.android.ugc.aweme:id/tw").click()
                    #返回
                    self.d(resourceId="com.ss.android.ugc.aweme:id/et").dlick()
                if self.d(resourceId="com.ss.android.ugc.aweme:id/yy", text="我").exists:
                    # 进入正常的视频页面,开始滑动
                    x1 = int(self.size[0] * 0.5)
                    y1 = int(self.size[1] * 0.9)
                    y2 = int(self.size[1] * 0.15)
                    self.d.swipe(x1,y1,x1,y2)
                    
if __name__ == '__main__':
    d = Douyin()
    d.swipe_douyin()
通过mitmproxy解析短视频App返回数据
#特别注意:
#在新版本的抖音中,我们是找不到正常的数据返回的
#当前使用的是10.0版本的抖音app,大家- -定要注意
#个人信息页接口
# https://aweme-eagle.snssdk.com/aweme/v1/user/?user_id
#滑动视频的接口
# https://aweme-eaple.snssdk.com/aweme/v1lfeed

import json

def response(flow):
    """解析10版本抖音app返回数据"""
    # 视频
    if 'https://aweme-eagle.snssdk.com/aweme/v1/feed' in flow.request.url:
        # 使用json 来loadsresponse.text
        video_response = json.loads(flow.response.text)
        video_list = video_response.get("aweme_list",[])
        for item in video list:
            print(item.get("desc"), "")
        
    #发布者页面
    if 'https://aweme-eagle.snssdk.com/aweme/v1/user/?user_id' in flow.request.url:
        person_response = json.loads(flow.response.text)
        person_info = person_response.get("user", "")
        if person_info:
            info = {
                'nickname': person_info.get("nickname", ""),
                'total_favorited': person_info.get("total_favorited",0)
                'following_count' : person_info.get("following_count", 0),
                'douyin_id': person_info.get("unique_id", ""),
                'follower_count' : person_info.get("follower_count", 0)
            }
            print(info)
  • 运行文件

mitmdump -s decode_douyin.py -p 8889

atxserver2库

atxserver2:
ATX2是一款可以远程控制Android和iOS设备的设备 管理平台。
该平台使用的技术栈为:Python3+ NodeJS + RethinkDB

······
省略
atxserver2通过pip安装部署
atxserver2多设备管理库的使用
实现多任务端app应用数据抓取系统

相关文章

网友评论

      本文标题:2020移动端python爬虫实战笔记

      本文链接:https://www.haomeiwen.com/subject/zeidsktx.html