欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用appium爬取数据python3实现

程序员文章站 2022-03-20 08:25:08
...

一、前言 
上一篇小说爬的是电脑端的静态网址,一直想爬手机端app数据的抓取,研究有好几天了,在网上也找了各种教程,差点挂在appium的环境安装。本编教程从appium的环境配置开始到抓取手机app微信朋友圈结束。 
知乎:https://zhuanlan.zhihu.com/p/41311503 
GitHub:https://github.com/FanShuixing/git_webspider

二、参考博文 
以下网址对于这篇教程非常重要,感谢分享

悠悠博主appium+python环境搭建:https://www.cnblogs.com/yoyoketang/p/6128725.html

崔大的appium环境搭建还有崔大的python3实战:https://cuiqingcai.com/5407.html

java环境配置:https://jingyan.baidu.com/article/fd8044fa2c22f15031137a2a.html

appium获取appPackage和appActivity:https://blog.csdn.net/mtbaby/article/details/78676477

在看这篇教程前,希望你已经具备selenium动态抓取网页的知识,若不熟悉,可参看https://blog.csdn.net/Fan_shui/article/details/81516645 
三、环境搭建 
我最开始是按照崔大的环境搭建 https://cuiqingcai.com/5407.html,然后弄完之后发现在notepad里面写的python运行不了,不能打开手机端的app,appium倒是可以打开。另外一篇环境搭建的博文安装的appium是旧版,我推荐先按照崔大的教程把appium环境和Android studio搭建下载好,重点:我们在安装的时候,安装环境只要是可以改的都改,不要按照默认的下在c盘,c盘就那么大个儿,最重要的是要清楚自己的安装位置,后面会用到。(当然也可以直接按照悠悠博主的教程一步步的搭建下来,若是这样,环境搭建下面就都可以不用看了) 
我们按照崔大的教程把appium环境+Android studio搭建好,其中第三步我再详细加一点,下图是崔大文中的第三步用appium爬取数据python3实现
我的安装位置在F:/SDK 
用appium爬取数据python3实现
在环境变量中,系统变量下增加一个这样 
用appium爬取数据python3实现 
在系统变量的path中增加个下面两个 
用appium爬取数据python3实现 
弄好后,我们打开另外一篇博文https://www.cnblogs.com/yoyoketang/p/6128725.html,一步步按照教程来,其中第三步、四步android_sdk下载就不用再下了,崔大的博文中已经下过。(ps:悠悠博主的后面几篇环境搭建也要看)

四、appium的使用 
恭喜恭喜,走到这一步,我走到这儿可是花了好几天的时间。本文使用的真机,没用模拟器,感兴趣的可以搜下模拟器的使用。我们用usb连接上手机,要打开手机上的usb调试,然后输入adb devices -l(不是数字1,是小写l) 
用appium爬取数据python3实现
出现上图就证明手机和电脑连接成功,若是出现下图这种,就把手机拔掉再重连一下 
用appium爬取数据python3实现 
成功后,打开appium 
用appium爬取数据python3实现

用appium爬取数据python3实现
platformName:平台名称 
deviceName:设备名称,就是刚才的adb devices -l中mode后面就是 
appPackage:app包名 
appActivity:app活动名

有个简单的方法便可以获得appPackage和appActivity:https://blog.csdn.net/mtbaby/article/details/78676477

start sessions后 
用appium爬取数据python3实现
我们可以点击左边的登陆(忍不住抱怨下微信,我不就是多登陆了两下,然后微信号被封了一天(*  ̄︿ ̄)),点击登陆后可以看到中间的App Source有高亮的代码,就是这个登陆按钮的,可以再看右边的Selected Element中有Tap、Send keys、Clear。 
在最左边图中点击登陆后,若最右边下面的clickable是True,则证明可以点击,可以通过点击Tap实现点击功能,appium就介绍到这。

五、python对接Appium

首先我们要对接app,就是类似于start session这样的连接 
注:代码运行时要保证手机不黑屏

from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait

PLATFORM='Android'
deviceName='HUAWEI_P7_L09'
app_package='com.tencent.mm'
app_activity='.ui.LauncherUI'
driver_server='http://127.0.0.1:4723/wd/hub'

class Moments():
    def __init__(self):
        self.desired_caps={
        'platformName':PLATFORM,
        'deviceName':deviceName,
        'appPackage':app_package,
        'appActivity':app_activity}
        self.driver=webdriver.Remote(driver_server,self.desired_caps)
        self.wait=WebDriverWait(self.driver,300)

    def login(self):
        print('正在登陆中——————')

    def main(self):
        self.login()

M=Moments()
M.main()

如果出现 urllib.error.URLError: urlopen error [WinError 10061] 由于目标计算机积极拒绝,无法连接。 
看看打开appium没有,打开后再运行上面的代码就没有问题,手机会自动转到微信的登陆界面(注:deviceName要改成自己手机的) 
用appium爬取数据python3实现 
打开微信后,我们要模拟点击登陆按钮,首先要定位到登陆元素,这个跟selenium的用法类似,我们可以打开appium用前面的方式连接微信,也可以打开sdk安装路径下tools中的uiautomatorviewer.bat,第二种方法比较快 
用appium爬取数据python3实现 
下图中,要先点击图中的按钮,才会出现手机上的画面,图中我已经定位到登陆按钮,可以在右边看到属性resource-id,以及clickable=True,确实是可以点击的,为什么要这样确认下呢,因为有的你以为可以点击的元素,也许你定位没有定好,比如说你定位到登陆外更大的一个框,它是不可点击的 
用appium爬取数据python3实现

from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

PLATFORM='Android'
deviceName='HUAWEI_P7_L09'
app_package='com.tencent.mm'
app_activity='.ui.LauncherUI'
driver_server='http://127.0.0.1:4723/wd/hub'

class Moments():
    def __init__(self):
        self.desired_caps={
        'platformName':PLATFORM,
        'deviceName':deviceName,
        'appPackage':app_package,
        'appActivity':app_activity}
        self.driver=webdriver.Remote(driver_server,self.desired_caps)
        self.wait=WebDriverWait(self.driver,300)

    def login(self):
        print('点击登陆按钮——————')
        login=self.wait.until(EC.presence_of_element_located((By.ID,'com.tencent.mm:id/d75')))
        login.click()

    def main(self):
        self.login()

M=Moments()
M.main()

运行后就会跳出登陆界面,接下来就都是定位元素与点击元素的事情:

from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

PLATFORM='Android'
deviceName='HUAWEI_P7_L09'
app_package='com.tencent.mm'
app_activity='.ui.LauncherUI'
driver_server='http://127.0.0.1:4723/wd/hub'

class Moments():
    def __init__(self):
        self.desired_caps={
        'platformName':PLATFORM,
        'deviceName':deviceName,
        'appPackage':app_package,
        'appActivity':app_activity}
        self.driver=webdriver.Remote(driver_server,self.desired_caps)
        self.wait=WebDriverWait(self.driver,300)

    def login(self):
        print('点击登陆按钮——————')
        login=self.wait.until(EC.presence_of_element_located((By.ID,'com.tencent.mm:id/d75')))
        login.click()
        #输入手机号
        phone=self.wait.until(EC.presence_of_element_located((By.ID,    'com.tencent.mm:id/hz')))
        phone_num=input('请输入手机号')
        phone.send_keys(phone_num)
        print('点击下一步中')
        button=self.wait.until(EC.presence_of_element_located((By.ID,       'com.tencent.mm:id/alr')))
        button.click()
        pass_w=input('请输入密码:')
        password=self.wait.until(EC.presence_of_element_located((By.ID,'com.tencent.mm:id/hz')))
        password.send_keys(pass_w)

        login=self.driver.find_element_by_id('com.tencent.mm:id/alr')
        login.click()
        #提示 叉掉
        tip=self.wait.until(EC.element_to_be_clickable((By.ID,'com.tencent.mm:id/an2')))
        tip.click()

    def main(self):
        self.login()

M=Moments()
M.main()

现在已经进入到微信了,我们需要先定位到微信下面的 发现->朋友圈

from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
PLATFORM='Android'
deviceName='HUAWEI_P7_L09'
app_package='com.tencent.mm'
app_activity='.ui.LauncherUI'
driver_server='http://127.0.0.1:4723/wd/hub'

class Moments():
    def __init__(self):
        self.desired_caps={
        'platformName':PLATFORM,
        'deviceName':deviceName,
        'appPackage':app_package,
        'appActivity':app_activity}
        self.driver=webdriver.Remote(driver_server,self.desired_caps)
        self.wait=WebDriverWait(self.driver,300)

    def login(self):
        print('点击登陆按钮——————')
        login=self.wait.until(EC.presence_of_element_located((By.ID,'com.tencent.mm:id/d75')))
        login.click()
        #输入手机号
        phone=self.wait.until(EC.presence_of_element_located((By.ID,    'com.tencent.mm:id/hz')))
        phone_num=input('请输入手机号')
        phone.send_keys(phone_num)
        print('点击下一步中')
        button=self.wait.until(EC.presence_of_element_located((By.ID,       'com.tencent.mm:id/alr')))
        button.click()
        pass_w=input('请输入密码:')
        password=self.wait.until(EC.presence_of_element_located((By.ID,'com.tencent.mm:id/hz')))
        password.send_keys(pass_w)

        login=self.driver.find_element_by_id('com.tencent.mm:id/alr')
        login.click()
        #提示 叉掉
        tip=self.wait.until(EC.element_to_be_clickable((By.ID,'com.tencent.mm:id/an2')))
        tip.click()

    def enter(self):
        print('点击发现——')
        tab=self.wait.until(EC.element_to_be_clickable((By.XPATH,'//*[@resource-id="com.tencent.mm:id/cdh"]/..')))
        print('已经找到发现按钮')
        time.sleep(6)
        tab.click()
        # self.wait.until(EC.text_to_be_present_in_element((By.ID,'com.tencent.mm:id/cdj'),'发现'))
        print('点击朋友圈')
        friends=self.wait.until(EC.presence_of_element_located((By.XPATH,'//*[@resource-id="android:id/list"]/*[@class="android.widget.LinearLayout"][1]')))
        friends.click()

    def main(self):
        self.login()
        self.enter()

M=Moments()
M.main()

都是些元素定位,多用几次就会了。接下来我们可以提取数据了

from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
import pymongo
PLATFORM='Android'
deviceName='HUAWEI_P7_L09'
app_package='com.tencent.mm'
app_activity='.ui.LauncherUI'
driver_server='http://127.0.0.1:4723/wd/hub'

class Moments():
    def __init__(self):
        self.desired_caps={
        'platformName':PLATFORM,
        'deviceName':deviceName,
        'appPackage':app_package,
        'appActivity':app_activity}
        self.driver=webdriver.Remote(driver_server,self.desired_caps)
        self.wait=WebDriverWait(self.driver,300)
        self.client=pymongo.MongoClient()
        self.db=self.client.weixin
        self.collection=self.db.weixin

    def login(self):
        print('点击登陆按钮——————')
        login=self.wait.until(EC.presence_of_element_located((By.ID,'com.tencent.mm:id/d75')))
        login.click()
        #输入手机号
        phone=self.wait.until(EC.presence_of_element_located((By.ID,    'com.tencent.mm:id/hz')))
        phone_num=input('请输入手机号:')
        phone.send_keys(phone_num)
        print('点击下一步中')
        button=self.wait.until(EC.presence_of_element_located((By.ID,       'com.tencent.mm:id/alr')))
        button.click()
        pass_w=input('请输入密码:')
        password=self.wait.until(EC.presence_of_element_located((By.ID,'com.tencent.mm:id/hz')))
        password.send_keys(pass_w)

        login=self.driver.find_element_by_id('com.tencent.mm:id/alr')
        login.click()
        #提示 叉掉
        tip=self.wait.until(EC.element_to_be_clickable((By.ID,'com.tencent.mm:id/an2')))
        tip.click()

    def enter(self):
        print('点击发现——')
        tab=self.wait.until(EC.element_to_be_clickable((By.XPATH,'//*[@resource-id="com.tencent.mm:id/cdh"]/..')))
        print('已经找到发现按钮')
        time.sleep(6)
        tab.click()
        # self.wait.until(EC.text_to_be_present_in_element((By.ID,'com.tencent.mm:id/cdj'),'发现'))
        print('点击朋友圈')
        friends=self.wait.until(EC.presence_of_element_located((By.XPATH,'//*[@resource-id="android:id/list"]/*[@class="android.widget.LinearLayout"][1]')))
        friends.click()

    def crawl(self):
        while True:
            items=self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//*[@resource-id="com.tencent.mm:id/dja"]//*[@class="android.widget.FrameLayout"]')))
            self.driver.swipe(300,1000,300,300)
            for item in items:
                try:
                    nickname=item.find_element_by_id('com.tencent.mm:id/as6').get_attribute('text')
                    print(nickname)
                    content=item.find_element_by_id('com.tencent.mm:id/dkf').get_attribute('text')
                    print(content)
                    data={'nickname':nickname,
                    'content':content}
                    self.collection.update({'nickname':nickname,'content':content},{'$set':data},True)

                except:
                    pass


    def main(self):
        self.login()
        self.enter()
        self.crawl()

M=Moments()
M.main()

driver.swipe()是从点A滑动到点B,driver.swipe(300,1000,300,300)是从点(300,1000)滑动到(300,300)

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

首先根据昵称和正文来查询,如果信息不存在,则插入数据,否则更新数据,关键点是第三个参数True,这可以实现存在即更新,不存在即插入的代码,用着感觉很舒服呢 
用appium爬取数据python3实现

总的来说,感觉学appium挺不容易的,开头就有个环境配置,后面再加上appium对接python的时候超级慢,调试要等很久,再加上微信次数登多了会被封一天,所以这篇教程花了很多时间,在这段时间内下一篇mitmdump都已经诞生了………

相关标签: appium