「docker实战篇」python的docker- 多设备端并发抓取抖音粉丝数据(23)
2019-06-13 11:08:05
李明
  • 访问次数: 382
  • 注册日期: 2018-07-09
  • 最后登录: 2022-11-17

原创文章,欢迎转载。转载请注明:转载自 IT人故事会,谢谢!
原文链接地址: 「docker实战篇」python的docker- 多设备端并发抓取抖音粉丝数据(23)

之前的文章搞过,抖音web端用户信息的抓取和抖音app端粉丝的抓取。一台设备抓取抖音粉丝数据实在是太慢了,这次咱们来演示下多模拟器同时爬取信息。源码: https://github.com/limingios/dockerpython.git (源码/「docker实战篇」python的docker- 多设备端并发抓取抖音粉丝数据(22))

16b4ecdd01871a1c?w=1196&h=411&f=png&s=58

拷贝之前的带xponsed的模拟器

  • 1.桌面有夜神模拟器多开
16b4ecdd03c98e28?w=238&h=54&f=png&s=1997
  • 2.选择中,点击复制,可能一下复制出来3个,咱们不需要那么多删除2个就可以了,你如果电脑足够强大也可以复制多个,下面代码的思路是一样的。
16b4ecdd02c7adfe?w=1240&h=364&f=png&s=80
  • 3.复制完成后,改下别名,方便区别
16b4ecdd1076239b?w=1240&h=345&f=png&s=74
    1. 启动2个模拟器。
16b4ecdd109718f7?w=1240&h=1088&f=png&s=1

多任务抓取

按照常理一般的互联网操作,如果要实现多任务抓取基本都是使用容器化的来完成的,但是目前直接说docker有点尚早,不过这个系列肯定是要实现docker的多设备抓取的,这里先说说使用python多进程的方式来完成。

  • 1.查看夜神模拟器的端口,启动cmd,输入
adb devices
16b4ecdd108dc5ea?w=653&h=231&f=png&s=400
  • 2.如果输入adb devices没有列表

在启动夜神模拟器的时候adb还没启动。也就是夜神模拟器比adb先启动,解决方案。
1.打开任务管理器,查看夜神模拟器的PID,可以通过点击状态-选中PID

16b4ecdd25c410e6?w=1240&h=1116&f=png&s=2

2.刚查看到的PID

netstat -ano | findstr "452"
16b4ecdd2a214f0e?w=1240&h=500&f=png&s=31
netstat -ano | findstr "16712"
16b4ecdd350a5ff1?w=1240&h=460&f=png&s=19

3.夜神模拟器端口是有规律的,第一个模拟器端口是62001,第二个是62025,第三个62025+1,第4个62025+2

16b4ecdd490f36e3?w=596&h=174&f=png&s=368
  1. 手动的命令方式连接设备
adb connect 127.0.0.1:62025
16b4ecdd465d5d13?w=712&h=88&f=png&s=3133

5.appium【客户端】需要设置udid,在appium里面识别就是udid,因为之前是一台设备所以不需要指定udid,光指定deviceName就可以了。

16b4ecdd4fc20dec?w=1076&h=560&f=png&s=48
  1. appium【服务端】需要设置bootstrapPort,服务端进行设置,设备和appium通信的端口。
16b4ecdd5200d6ef?w=1240&h=487&f=png&s=76
16b4ecdd5ccd5765?w=1240&h=933&f=png&s=95
16b4ecdd5e691734?w=1240&h=509&f=png&s=29

7.appium的2台的属性设置
1.douyin1 port=4723 bootstrapPort=4724
2.douyin1 port=4725 bootstrapPort=4726

16b4ecdd6f4f3249?w=1240&h=393&f=png&s=46
16b4ecdd77d5e678?w=1240&h=631&f=png&s=76
    1. 报错解决方案

selenium.common.exceptions.WebDriverException: Message: An unknown server-side error occurred while processing the command. Original error: Failed to Dump Window Hierarchy

16b4ecdd869d546e?w=1240&h=113&f=png&s=13

解决方案
在含有Emoji特殊符号的页面中,爆出Failed to Dump Window Hierarchy
https://github.com/appium/appium/issues/4151
http://blog.csdn.net/soslinken/article/details/50126477
won’t be solved until the new android driver is completed. This is a known bug in uiautomator v1
此问题是uiautomator自身bug,换用Android5.1以上的系统

源码

#!/usr/bin/env python
import time
from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
import multiprocessing
def get_size(driver):
    x = driver.get_window_size()['width']
    y = driver.get_window_size()['height']
    return (x, y)
def handle_douyin(driver):
    while True:
        #定位搜索框
        if WebDriverWait(driver,60).until(lambda x:x.find_element_by_xpath("//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[2]/android.widget.EditText[1]")):
            #获取douyin_id进行搜索
            driver.find_element_by_xpath("//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[2]/android.widget.EditText[1]").send_keys('1860719705')
            while driver.find_element_by_xpath("//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[2]/android.widget.EditText[1]").text != '1860719705':
                driver.find_element_by_xpath("//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[2]/android.widget.EditText[1]").send_keys('1860719705')
                time.sleep(0.1)
        #点击搜索
        driver.find_element_by_xpath("//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/android.widget.TextView[1]").click()
        #点击用户标签
        if WebDriverWait(driver,30).until(lambda x:x.find_element_by_xpath("//android.widget.TextView[@text='用户']")):
            driver.find_element_by_xpath("//android.widget.TextView[@text='用户']").click()
        #点击头像
        if WebDriverWait(driver,30).until(lambda x:x.find_element_by_xpath("//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.support.v4.view.ViewPager[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[2]/android.view.View[1]/android.support.v7.widget.RecyclerView[1]/android.widget.RelativeLayout[1]/android.widget.RelativeLayout[1]/android.widget.ImageView[1]")):
            driver.find_element_by_xpath("//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.support.v4.view.ViewPager[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[2]/android.view.View[1]/android.support.v7.widget.RecyclerView[1]/android.widget.RelativeLayout[1]/android.widget.RelativeLayout[1]/android.widget.ImageView[1]").click()
        #点击粉丝按钮
        if WebDriverWait(driver,30).until(lambda x:x.find_element_by_xpath("//android.widget.TextView[@text='粉丝']")):
            driver.find_element_by_xpath("//android.widget.TextView[@text='粉丝']").click()
            x1 = int(driver.get_window_size()['width']*0.5)
            y1 = int(driver.get_window_size()['height']*0.75)
            y2 = int(driver.get_window_size()['height']*0.25)
            while True:
                time.sleep(3)
                if '没有更多了' in driver.page_source:
                    break
                elif 'TA还没有粉丝' in  driver.page_source:
                    break
                else:
                    driver.swipe(x1,y1,x1,y2)
                    time.sleep(0.5)
            #返回
            driver.find_element_by_xpath("//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/android.widget.RelativeLayout[1]/android.widget.FrameLayout[1]/android.widget.ImageView[1]").click()
            #返回
            driver.find_element_by_id("com.ss.android.ugc.aweme:id/jk").click()
            #重新清空用户id
            driver.find_element_by_xpath("//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[2]/android.widget.EditText[1]").clear()
def handle_appium(device,port):
    cap = {
        "platformName": "Android",
        "platformVersion": "4.4.2",
        "deviceName": device,
        "udid":device,
        # 真机的
        # "platformName": "Android",
        # "platformVersion": "7.1.2",
        # "deviceName": "10d4e4387d74",
        "appPackage": "com.ss.android.ugc.aweme",
        "appActivity": "com.ss.android.ugc.aweme.main.MainActivity",
        "noReset": True,
        "unicodeKeyboard": True,
        "resetkeyboard": True
    }
    driver = webdriver.Remote("http://localhost:"+str(port)+"/wd/hub", cap)
    try:
        # 点击搜索
        print('点击搜索')
        if WebDriverWait(driver, 60).until(lambda x: x.find_element_by_xpath(
                "//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.support.v4.view.ViewPager[1]/android.widget.FrameLayout[1]/android.support.v4.view.ViewPager[1]/android.widget.TabHost[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.view.View[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.widget.LinearLayout[2]/android.widget.FrameLayout[1]/android.widget.ImageView[1]")):
            driver.find_element_by_xpath(
                "//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.support.v4.view.ViewPager[1]/android.widget.FrameLayout[1]/android.support.v4.view.ViewPager[1]/android.widget.TabHost[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.view.View[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.widget.LinearLayout[2]/android.widget.FrameLayout[1]/android.widget.ImageView[1]").click()
    except:
        # [26,76][115,165]
        driver.tap([(26, 76), (115, 165)], 500)
    handle_douyin(driver)
if __name__ == '__main__':
    m_list = []
    #定义了2台虚拟设备,夜神模拟器
    devices_list = ["127.0.0.1:62001","127.0.0.1:62025"]
    for device in range(len(devices_list)):
        port = 4723 + 2 * device
        m_list.append(multiprocessing.Process(target=handle_appium,args=(devices_list[device],port,)))
    for m1 in m_list:
        m1.start()
    for m2 in m_list:
        m2.join()

启动步骤

  • 1.启动2个appium

之前上边已经提到过的端口(4723 4724 )(4725 4726)

16b4ecdd8cb07dd4?w=1213&h=887&f=png&s=10
  • 2.启动python代码,查看效果

调试测试代码次数太多了,douyin要求我登录,哈哈

16b4ecdd9e4b2fbb?w=1240&h=638&f=png&s=29

伪装爬虫

刚出现的因为访问册数太多,douyin那边识别了,这样需要解决。通过代理的方式。

16b4ecdda1a1bb72?w=1240&h=571&f=png&s=22
16b4ecddb1cc4f93?w=1240&h=595&f=png&s=12
  • 2.登录【阿布云】后,使用mitmdump的方式,设置阿布云的代理

启动cmd,输入
mitmdump -s test.py -p 8889 --mode upstream:HTTP隧道服务器:端口 --upstream-auth 通行证书:通行秘钥

mitmdump -s test.py -p 8889 --mode upstream:http://http-pro.abuyun.com:9010 --upstream-auth HS821YO6BA7D6M8P:75021E5CF3AB82EE
16b4ecddb6e6c6a3?w=1240&h=95&f=png&s=979
  • 3.模拟器的wifi也要设置对应的代理,之前说过在重复说下。
16b4ecddac4d3ac5?w=724&h=1312&f=png&s=11
  • 4.这样就使用了代理的方式了。 所有请求就是代理的阿布云了。

感谢老铁的建议,以后的所有的系列的源码都是按照对应文章进行整理,原来的源码都是按照我的开发历程的,这样不适合中间参与进来的老铁。

PS:调试过程中,夜神模拟器,appium,python代码插件没有问题的话,程序在运行过程中出现的最多的问题还是xpath定位的问题,对于python的代码其实也是很好理解的。另外注意的文章中提到的要使用安卓5.1以上否则会因为页面中含有Emoji特殊符号,爆出Failed to Dump Window Hierarchy。udid对于启动多个模拟器的时候一定要进行设置。

16b4ecddbf5bb4d6?w=1080&h=541&f=png&s=45