使用Appium爬取淘宝App数据

0x01、介绍说明

1、简介

图片
Appium是一个自动化测试开源工具。通过WebDriver协议驱动IOS、Android、Windows Phone平台上的原生应用、混合应用和web应用。

2、Appium工作原理

Appium选择了Client/Server的设计模式,Server可以在OSX、Windows以及Linux系统上运行,Client支持Ruby、Python、Java、PHP、C#、JavaScript等语言的实现。

当我在MAC平台上,通过Python(python-client )编写了一个appium自动化脚本并执行,请求会首先到 appium.dum (MAC下的appium-Server),appium-Server通过解析,驱动iOS设备来执行appium自动化脚本。或者,我在Windows平台上,通过Java( java-client )编写了一个appium自动化脚本并执行,请求会首先到 appiumForWindow.zip(Window下的appium-Server),appium-Server通过解析,驱动Android虚拟机或真机来执行appium脚本。所以,你会看到appium的强大之处就在于此。

0x02、环境配置

本教程以MacBook Pro通过Python程序控制Android系统的淘宝App为例,因为Appium依赖Android SDK,Android SDK需要Java环境,所以所需环境如下:

  • Java
  • Android SDK
  • Appium
  • Python

1、 Java安装

# 在终端输入以下命令
java -version

# 命令反馈信息,说明安装成功
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)
  • 配置环境:
# 打开.bash_profile文件
vim ~/.bash_profile

# 配置环境变量(路径需要更改为自己的Java安装路径),保存并退出
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home
export CLASS_PATH=$JAVA_HOME/lib
export PATH=$PATH:$JAVA_HOME/bin

# 配置生效
source ~/.bash_profile

2、Android SDK 安装

  • 下载:下载地址
  • 解压:进入目录android-sdk-macoxs --> tool, 双击android文件来启动Android SDK Manager
  • Android SDK Manager:
    • SDK Path: 安装路径
    • 只需要安装Android SDK Tolls 、Android SDK Platform-tools和Android SDK Build-tools(默认会选中Android 9的模拟系统,如果下载了Android的模拟系统,只有无尽等待)
    • 点击 install
图片
  • 配置环境
# 打开.bash_profile
vim ~/.bash_profile

# 输入自己的路径,保存并退出
export ANDROID_HOME=/Users/xxxxxxx/Documents/Android/android-sdk-macosx
export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools

# 使配置生效
vim ~/.bash_profile

# 输入命令,查看是否成功
adb --version
# 出现-bash: adb: command not found错误,常见原因有两种
# 1. 环境变量配置出错
# 2. 重启电脑(至于为什么需要重启,母鸡啊)

3、Appium 安装

# 先安装brew, 如果已经安装过了请跳过
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew update

# 再安装npm:
brew install npm

# 安装cnpm:淘宝NPM镜像
npm install -g cnpm --registry=https://registry.npm.taobao.org

# 用cnpm安装appium
cnpm install -g appium

# 检测是否成功
appium

# 安装appium-doctor, 该软件能够检测appium正常运行所需要的环境是否都有
npm install appium-doctor -g

# 然后检测是环境配置好,如果出错重启电脑
appium-doctor 
  • 根据appium-doctor反馈结果安装所需环境
# Xcode是控制ios的,暂时不用问

# Carthage was NOT founf! 解决办法
brew install carthage
图片

4、Python3安装

图片

图片
  • 安装:按照步骤安装就行
  • python2和python3共存
# mac 输入python命令默认是python2.7,通过以下命令查看不同python版本所在的目录
which python
which python2
which python3

# 创建软链接,python2和python3共存
# python2.7的软连接设置为python2
ln -s /usr/bin/python2.7 /usr/bin/python2

# 删除原有的python的软连接
rm /usr/bin/python
# 把python3的软连接设置为python
ln -s /usr/local/bin/python3 /usr/bin/python

0x03、建立连接

pc端和移动端的连接有两种方式USB连接和无线连接

1、 USB连接

  • 打开开发者模式和USB调试:允许USB安装、USB调试等权限
  • 打开pc终端
# 查看手机设备信息
adb devices 

# 命令反馈信息,出现设备id号说明连接成功
* daemon not running; starting now at tcp:5037
* daemon started successfully
xxxxxxx unauthorized

2、无线连接

  • 在USB连接下,输入 adb tcpip 5555
# 端口号是任意的,只要不被占用就行
adb tcpip 5555

# 命令反馈信息
restarting in TCP mode port: 5555
  • 查看手机设备局域网ip
# 查看手机设备的局域网ip
adb shell ip -f inet addr show wlan0 

# 命令反馈信息,其中192.168.1.5就是内网ip,或者在手机端的wifi设置查看
* 22: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000

    inet 192.168.1.5/24 brd 192.168.1.255 scope global wlan0

       valid_lft forever preferred_lft forever
  • 无线连接
# ip需要改为你手机设置的ip
adb connect 192.168.1.5

# 命令反馈信息,说明连接成功,就可以不需要USB数据线连接了,但是pc端和移动端需要在同一个局域网下
connected to 192.168.1.5:5555
  • 验证
# 断掉USB连接,输入以下命令
adb devices

# 命令反馈信息,此时手机的设备号就变成192.168.1.5:5555了
List of devices attached
192.168.1.5:5555    device

3、 SDK 命令

adb kill-server          # 断开连接
adb install path_to_apk  # 通过命令安装app

更多命令:官方教程

0x04、控制程序

1、运行appium

# 启动命令。4444 端口号(可以随意设置,官方建议>=4444)、192.168.1.5:5555:获取到的手机设备号,在python程序里会用到。当程序python运行之后,该命令会打印操作日志
appium -a 127.0.0.1 -p 4444 -U 192.168.1.5:5555

2、程序

  • 所需python库
pip install Appium-Python-Client
pip install selenium
  • 定位元素
# 打开终端输入UIAutomatorviewer,就可以查看定位元素了
UIAutomatorviewer
图片
  • 爬取淘宝app
import time
from appium import webdriver
from appium.webdriver.common import mobileby
from appium.webdriver.webdriver import WebDriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


desired_capabilities = {
        'platformName': 'Android',                          # 系统
        'deviceName': 'xxxxxxxx',                           # 移动设备号
        'platformVersion': '6.0.1',                         # 系统版本
        'appPackage': 'com.taobao.taobao',                  # 操作的app
        'appActivity': 'com.taobao.tao.welcome.Welcome',    # 打开淘宝app首页
        'unicodeKeyboard': True,
        'resetKeyboard': True,
        'dontStopAppOnReset': True,
        'autoGrantPermissions': True,
        'noReset': True,
        'automationName': 'uiautomator2',
        'newCommandTimeout': '36000',                       # 超时时间
        'systemPort': '8202',                               # 端口号,操作不用设备使用不同端口号
        'udid': 'xxxxxxxx',                                 # 移动设备号
        'command_executor': 'http://127.0.0.1:4444/wd/hub'  # 和启动命令保持一致
}


class AppiumDemo(object):
    def __init__(self):
        self.driver = webdriver.Remote(command_executor=desired_capabilities['command_executor'],
                                       desired_capabilities=desired_capabilities)
        self.by = mobileby.MobileBy()

        # 点击搜索框
        self.wait_find_element(by_type=self.by.ID, value='com.taobao.taobao:id/home_searchedit').click()
        # 点击店铺搜索
        self.wait_find_element(by_type=self.by.XPATH, value='//android.widget.TextView[@text="店铺"]').click()

    def wait_find_element(self, by_type: str, value: str, driver: WebDriver = None):
        """
        获取单个元素, 显式等待
        :param driver: 驱动对象
        :param by_type: 查找元素的操作
        :param value: 查找元素的方法
        :return:
        """
        driver = driver or self.driver
        if not driver:
            return driver
        try:
            WebDriverWait(driver, 10).until(EC.visibility_of_element_located(locator=(by_type, value)))
            return driver.find_element(by_type, value)
        except:
            # self.logger.warning(traceback.format_exc())
            return False

    def wait_find_elements(self, by_type: str, value: str, driver: WebDriver = None):
        """
        获取多个元素, 显式等待
        :param driver:
        :param by_type:
        :param value:
        :return:
        """
        driver = driver or self.driver
        if not driver:
            return driver
        try:
            WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located(locator=(by_type, value)))
            return driver.find_elements(by_type, value)
        except:
            return False

    def get_size(self, driver: WebDriver = None):
        """
        获取屏幕大小
        :param driver:
        :return:
        """
        driver = driver or self.driver
        if not driver:
            return driver

        x = driver.get_window_size()['width']
        y = driver.get_window_size()['height']
        return [x, y]

    def swipe_up(self, driver: WebDriver = None, _time: int = 1000):
        """
        向上滑动
        :param driver:
        :param _time:
        :return:
        """
        driver = driver or self.driver
        if not driver:
            return driver
        try:
            size = self.get_size(driver)
            x1 = int(size[0] * 0.5)  # 起始x坐标
            y1 = int(size[1] * 0.80)  # 起始y坐标
            y2 = int(size[1] * 0.30)  # 终点y坐标
            driver.swipe(x1, y1, x1, y2, _time)
            return True
        except:
            return False

    def execute(self, seed):
        self.wait_find_element(by_type=self.by.ID, value='com.taobao.taobao:id/searchEdit').clear().send_keys(seed['keyword'])
        self.wait_find_element(by_type=self.by.ID, value='com.taobao.taobao:id/searchbtn').click()
        self.wait_find_element(by_type=self.by.XPATH, value='//android.widget.TextView[@text="销量优先"]').click()
        shop_list = self.wait_find_elements(by_type=self.by.ID, value='com.taobao.taobao:id/shopTitle')
        for shop_info in shop_list:
            shop_info.click()
            # 点击全部宝贝
            self.wait_find_element(by_type=self.by.XPATH, value='//android.widget.FrameLayout'
                                                                '[@content-desc="全部宝贝"]').click()

            for i in range(3):
                # 获取这一屏的数据
                item_list = self.wait_find_elements(by_type=self.by.ID, value="com.taobao.taobao:id/title")
                for item_info in item_list:
                    print(item_info.text)
                self.swipe_up()                 # 向上滑动
                time.sleep(0.5)                 # 一定要延时
            self.driver.back()                  # 返回上一级
        self.driver.back()


def main():
    seed = {
        'keyword': 'Python 书'
    }
    spider = AppiumDemo()
    while True:
        spider.execute(seed=seed)


if __name__ == '__main__':
    main()

程序第一次运行的时候,会在手机安装3个app,一定要同意安装,只有Appium Settings在桌面有图标

  • Appium Settings
  • io.appium.uiautomator2.server
  • io.appium.uiautomator2.server.test

0x05、参考

Android SDK官方教程
Appium官方教程
Appium新手入门

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342