Выйдите за рамки Appium и используйте Airtest для сверхбыстрой разработки сканеров приложений.

Python рептилия

Хотите разработать веб-краулер и обнаружить, что он был перевернут? Хотите захватить приложение и обнаружить, что данные зашифрованы? Не волнуйтесь, используя Airtest для разработки сканера приложений, пока человеческий глаз может его увидеть, вы можете его поймать. Это занимает всего 2 минуты в кратчайшие сроки. Он совместим с Unity3D, Cocos2dx-*, родным приложением для Android. , приложение iOS, Windows Mobile... .

Airtest — это инструмент для автоматизированного тестирования интерфейса мобильного пользовательского интерфейса, разработанный NetEase. Его первоначальная цель — упростить написание тестового кода графического интерфейса мобильного приложения с помощью WYSIWYG, щелчка по снимку экрана и других функций.

Основываясь на убеждении, что все инструменты в мире используются мной, а инструменты, которые позволяют мне получать данные, могут быть использованы для разработки краулеров, я решил использовать Airtest для разработки краулеров мобильных приложений.

установить и использовать

Поскольку цель этой статьи — рассказать, как использовать Airtest для разработки сканеров приложений, введение Airtest в качестве инструмента разработки тестов будет пропущено только для объяснения того, как устанавливать и выполнять основные операции.

Установить Airtest

С официального сайта Airtest:airtest.netease.comЗагрузите Airtest и установите его как обычное программное обеспечение. Ничего особенного в процессе установки нет. Airtest уже упаковал для вас все среды, необходимые для разработки, поэтому вы можете использовать его сразу после установки Airtest.

Интерфейс после запуска Airtest показан на рисунке ниже.

Подключи свой телефон

В качестве примера возьмем телефон Android, поскольку Airtest установит на телефон два вспомогательных приложения с помощью команды adb, а затем использует команду adb для управления двумя вспомогательными приложениями для управления телефоном, поэтому вам необходимо убедиться, что телефонadb调试Функция включена и позволяет установить приложение на телефон с помощью команды adb.

После запуска Airtest подключите телефон Android к компьютеру и нажмите на флажок на картинке ниже.refresh ADB:

На этом этапе вы должны увидеть информацию о телефоне в правом верхнем углу интерфейса Airtest, как показано на следующем рисунке.

нажмитеconnectКнопка, вы можете видеть интерфейс мобильного телефона на интерфейсе в это время, и когда вы вручную управляете экраном мобильного телефона, экран мобильного телефона в Airtest обновляется в режиме реального времени. Как показано ниже.

Для некоторых мобильных телефонов, таких как Xiaomi, при первом использовании Airtest обратите внимание, что на мобильном телефоне появится подсказка с вопросом, разрешить ли установку приложения.В это время вам нужно нажать Кнопка Разрешить.

Открыть WeChat

Давайте посмотрим, как быстро начать работу с Airtest на простом примере, а позже подробно объясним.

Например, теперь я хочу использовать свой компьютер для управления своим телефоном и открывать WeChat.

В этот момент щелкните поле на рисунке ниже.touchкнопка:

В этот момент подведите мышь к области экрана телефона с правой стороны Airtest, и мышь превратится в крестик. Нажмите и удерживайте левую кнопку мыши в верхнем левом углу значка WeChat и перетащите ее в правый нижний угол WeChat, чтобы отпустить мышь. В этот момент обратите внимание, что изменилось в области промежуточного кода, как показано на изображении ниже.

Хорошо. Это все, что вам нужно сделать, чтобы открыть WeChat на компьютере.

Щелкните значок треугольника на верхней панели инструментов, чтобы запустить код, как показано на следующем рисунке.

После запуска кода открывается WeChat.

Введение в интерфейс

После интуитивно понятного использования мы представим интерфейс Airtest, который будет более целенаправленным.

Интерфейс Airtest показан на рисунке ниже.

Здесь я разделил Airtest на области A-F6, и их функции следующие:

  • Зона A: часто используемая функциональная зона
  • Область B: область написания кода Python
  • Область C: Область журнала операций
  • Зона D: область экрана мобильного телефона
  • Область E: Область просмотра информации о макете страницы приложения
  • Область F: Панель инструментов

Область А обычно используется基于图像识别функции управления экраном, такие как:

  • touch: нажмите на элемент экрана
  • swipe: проведите по экрану
  • exists: определить, существует ли элемент экрана
  • text: введите текст в поле ввода.
  • snashot: снимок экрана
  • ...

Вообще говоря, нажмите на функцию в области A, а затем выполните операцию выбора кадра на экране в области D, и область B автоматически сгенерирует соответствующий код операции.

Область B используется для отображения и написания кода Python. В большинстве случаев нет необходимости писать код вручную, потому что код будет сгенерирован автоматически на основе ваших действий на экране телефона. Только некоторые действия, требующие специальной настройки, требуют модификации кода.

Область D показывает экран мобильного телефона. Когда вы работаете с настоящим мобильным телефоном, экран будет обновляться в режиме реального времени. Вы также можете использовать мышь для управления мобильным телефоном прямо на экране в области D, и ваши действия будут автоматически выполняться на реальном устройстве.

Область F — это некоторые часто используемые инструменты, расположенные слева направо в следующем порядке:

  1. Новый проект
  2. Открытый проект
  3. сохранить проект
  4. запустить код
  5. код остановки
  6. Просмотр отчетов о прогонах

Среди них 1-5 легко понять, так что же такое отчет о просмотре операции?

После того, как вы запустите его хотя бы один раз, щелкните эту функцию, и она автоматически откроет для вас веб-страницу. Веб-страница показана на рисунке ниже, который представляет собой текущий отчет о вашем коде с подробным описанием того, какие элементы используются на каждом этапе.

Хотя управлять мобильным телефоном с помощью функции скриншота удобно, скриншот связан с проблемой разрешения, и код нельзя использовать на разных мобильных телефонах. Поэтому для функции области А можно проделать несколько простых операций без глубокого понимания.

Более продвинутые функции должны быть реализованы через область E.

Управляйте телефоном на основе информации о макете приложения

код инициализации

Информация о макете приложения подобна HTML-коду веб-страницы, который сохраняет относительные позиции и параметры каждого элемента в приложении. Для Приложения на мобильных телефонах с разным разрешением один и тот же элемент может иметь разные точки координат, но параметры атрибута этого элемента обычно остаются неизменными. Поэтому, если вы используете параметры атрибута элемента для поиска и управления этим элементом, вы можете добиться точного позиционирования на мобильных телефонах с разным разрешением.

Формат информации о макете приложения связан со средой разработки приложения. Щелкните раскрывающееся меню в области F, и вы увидите, что здесь можно указать различные среды разработки приложений. один из нихUnity,Cocos-*Подождите, это обычно используется для игр.AndroidЭто собственное приложение для Android,iOSЭто приложение Apple... как показано ниже.

В качестве примера возьмем мобильную версию Zhihu.Поскольку это родное приложение для Android, выберите его в раскрывающемся меню в области F.Android, в это время обратите внимание на всплывающую подсказку в области B с вопросом, хотите ли вы вставить начальный код poco в позицию текущего курсора ввода, нажмитеYes,Как показано ниже.

В этот момент фрагмент кода автоматически вставляется в область B, как показано на следующем рисунке.

Найдите и нажмите

Теперь щелкните значок замка в области E, как показано на изображении ниже.

После того, как значок блокировки активирован, вы можете управлять экраном в области D, нажмите知乎Под приложением知乎Два слова, вы обнаружите, что приложение, нажатое на экран, не открывается. Однако области E и C изменились, как показано на рисунке ниже.

Древовидная структура, отображаемая в области E, представляет собой информацию о макете текущего экрана, точно такую ​​же, как структура HTML, отображаемая в инструментах разработчика Chrome. Область C отображает информацию об элементе, на который я нажимаю в данный момент.

Обратите внимание, что среди этой информации об элементах естьtextсвойство, его стоимость知乎. Затем этот атрибут можно использовать как элемент позиционирования, поэтому вы можете написать код в области B:

poco(text="知乎").click()

Запустите программу после написания кода, и вы увидите, что приложение Zhihu открыто. Как показано ниже.

Обратите внимание: если вы обнаружите, что интерфейс, отображаемый на реальном телефоне, не соответствует мобильному интерфейсу, отображаемому на экране Airtest, это может быть связано с тем, что экран Airtest заблокирован вами. Щелкните значок замка в области F, чтобы отменить блокировку, и экран телефона в Airtest обновится.

Найдите и введите

После открытия Zhihu я хочу использовать функцию поиска Zhihu, затем активировать значок блокировки, а затем щелкнуть поле поиска в верхней части Zhihu, как показано на следующем рисунке:

Продолжайте смотреть на свойства окна поиска, отображаемого в области C, вы можете видеть, что естьnameсвойство, его стоимостьcom.zhihu.android:id/input, есть еще одинtextсвойство, его стоимость蔡徐坤任 NBA 新春贺岁大使. Можете ли вы использовать то же самое, что и открытие Zhihu раньше?textА как насчет этого имущества? Все в порядке, это не работает. Скажите, что это работает, потому что вы делаете это, и это работает сейчас; скажите, что это не работает, потому что это популярное ключевое слово поиска на Zhihu, и оно может измениться в любое время. Если вы успешно используете это предложение сегодня, завтра популярные ключевые слова изменятся, и ваш код не будет работать. Поэтому вам нужно использоватьnameэто свойство.

Общие свойства, которые существенно не меняются, включают, но не ограничиваются:name type resourceId package.

Еще один момент заключается в том, что окно поиска на главной странице Zhihu на самом деле не может вводить контент, и когда вы щелкнете по нему, оно перейдет на другую страницу, как показано на рисунке ниже.

Поэтому вам нужно сначала щелкнуть это поле ввода, чтобы перейти к реальному интерфейсу поиска:

poco(name="com.zhihu.android:id/input").click()

Реальный интерфейс поиска показан ниже.

можно увидеть,nameСтоимость имущества по-прежнемуcom.zhihu.android:id/input, теперь вы можете ввести содержимое.

Метод, используемый для ввода содержимого,set_text, использование:

poco(name="com.zhihu.android:id/input").set_text('古剑奇谭三')

найти и отфильтровать

После ввода ключевых слов для поиска снова посмотрите на текущую страницу, в поиске есть три результата:

Сравнивая атрибутивную информацию этих трех результатов, обнаруживается, что ихnameсвойства одинаковы, аtextразные. Если вы напишете действие щелчка следующим образом:

poco(name='com.zhihu.android:id/magi_title').click()

По умолчанию будет нажат первый результат поиска.

Что делать, если я хочу нажать на второй результат поиска? Вы можете написать такой код:

poco(name='com.zhihu.android:id/magi_title', text='古剑奇谭(电视剧)').click()

Или вы также можете использовать позиционирование индекса, например список:

poco(name='com.zhihu.android:id/magi_title')[1].click()

Предпосылка обоих написаний заключается в том, что мы уже знаем, что представляет собой каждый результат. Предположим, теперь я хочу искать古剑奇谭三, но я не знаю, какой элемент является результатом поиска, что мне делать? Здесь также можно использовать регулярные выражения:

poco(name='com.zhihu.android:id/magi_title', textMatches='^古剑奇谭三.*$').click()

Проведите по экрану

После входа в результаты поиска вам нужно проверить различные вопросы ниже, и вам нужно постоянно двигать экран вверх. Здесь есть одна вещь, на которую стоит обратить особое внимание: Airtest может получить информацию только о расположении элементов на текущем экране, а контент, которого нет на экране, получить нельзя. Это отличается от Selenium.

Команда, используемая для прокрутки экрана,swipe, скользящий экран должен использовать информацию о координатах. Но такие координаты не зависят от разрешения экрана. здесь坐标Определяется как: (x, y), где x — абсцисса, а y — ордината. Верхний левый угол экрана равен (0, 0), а нижний правый угол экрана равен (1, 1).Слева направо абсцисса постепенно увеличивается от 0 до 1, а сверху вниз абсцисса ордината постепенно увеличивается от 0 до 1.

Теперь я хочу сдвинуть экран вверх, поэтому на реальной машине я сначала нажимаю и удерживаю нижнюю часть экрана, а затем сдвигаю экран вверх, поэтому код можно записать так:


# poco.swipe(起点坐标,终点左边)
poco.swipe([0.5, 0.8], [0.5, 0.2])

Схема ориентации показана на следующем рисунке:

при нормальных обстоятельствах:

  • Чтобы скользить вверх, вам нужно только изменить ординату, а значение начальной точки больше, чем значение конечной точки.
  • Чтобы скользить вниз, вам нужно только изменить ординату, а значение начальной точки меньше значения конечной точки.
  • Проведите пальцем влево, нужно только изменить абсциссу, и значение начальной точки больше, чем значение конечной точки
  • Проведите пальцем вправо, нужно только изменить абсциссу, а значение начальной точки меньше значения конечной точки

При разработке краулера в основном были введены задействованные операции Airtest.

Управляйте своим телефоном, используя только Python

Хотя в Airtest удобно работать с мобильным телефоном, установить Airtest на каждый компьютер невозможно. Поэтому нам нужно найти способ отделить код от программы Airtest.

Airtest разработан на основе Poco, библиотеки Python с открытым исходным кодом, и код Python, написанный в области B Airtest, на самом деле является кодом Poco. Итак, пока установлена ​​библиотека Poco, вы можете напрямую управлять телефоном в Python.

Команда для установки библиотеки Poco:

pip install pocoui

Эта библиотека зависит от многих вещей, и установка немного медленнее. После завершения установки копируем код в PyCharm, как показано на следующем рисунке.

Запустите этот код. Если вы являетесь пользователем Linux или macOS, обратите внимание, чтобы увидеть, есть ли ошибка в результатах выполнения, указывающая на то, что у adb нет разрешения на запуск. Это связано с тем, что adb, установленный с Poco, не имеет разрешения на запуск, вам нужно добавить ему разрешение и выполнить команду в терминале:

# chmod +x 报错信息中给出的adb地址

chmod +x /Users/kingname/.local/share/virtualenvs/ZhihuSpider/lib/python3.7/site-packages/airtest/core/android/static/adb/mac/adb(实际执行时请换成你的地址)

После того, как команда будет выполнена, выполните код еще раз.Вы можете видеть, что код работает успешно, и телефон успешно управляется, как показано на следующем рисунке.

Как получить текст на экране

Поскольку код в редакторе Airtest не может нормально печатать китайский язык после запуска, следующий код выполняется непосредственно в PyCharm.

Поскольку вы хотите быть поисковым роботом, вам нужно получить текстовый контент на свой мобильный телефон. Возвращаясь к странице поиска, я хочу знать, сколько результатов можно найти по ключевому слову «Гу Цзянь Ци Тан» три, и сколько обсуждений имеет каждый результат, как показано на следующем рисунке:

На этом этапе нам нужно сделать две вещи:

  1. Просмотр каждого результата поиска по отдельности
  2. Получить текст на экране

Древовидная структура области E показана на следующем рисунке:

Заголовок каждого результата поиска используется как значение текстового атрибута вname='com.zhihu.android:id/magi_title'В соответствующем элементе номер обсуждения каждого результата поиска используется как значение текстового атрибута, вname='com.zhihu.android:id/magi_count'в соответствующем элементе.

Самый простой способ — получить три заголовка и три номера обсуждения по отдельности и объединить их вместе:

title_obj_list = poco(name='com.zhihu.android:id/magi_title')
title_list = [title.get_text() for title in title_obj_list]

discuss_obj_list = poco(name='com.zhihu.android:id/magi_count')
discuss_list = [discuss.get_text() for discuss in discuss_obj_list]

for title, discuss in zip(title_list, discuss_list):
    print(title, discuss)

Эффект операции показан на следующем рисунке:

Но такой подход на самом деле очень опасен, если предположить, что будет очень редкий результат поиска, только в заголовке нет номера обсуждения, поэтому практика раздельного обхода и рекомбинации приведет к неуместному финальному совпадению. Поэтому разумно сначала уловить большое, а потом маленькое. Каждая группа заголовков и номеров обсуждений имеет собственный родительский узел, как показано тремя стрелками на рисунке ниже.android.widget.LinearLayout:

Итак, теперь используйте технику захвата большого, а затем малого, сначала захватите родительский узел каждой группы результатов, а затем перейдите к каждому результату, чтобы получить заголовок и количество обсуждений.

Но как получить этот родительский узел? Как показано на рисунке ниже, каждое значение атрибута этого родительского узла не является чем-то особенным, и запись любого из них может конфликтовать с другими узлами.

На этом этапе проще всего дважды щелкнуть родительский узел в области E. Код таргетинга добавляется автоматически, как показано на изображении ниже.

Этот код позиционирования выглядит очень сложным, но на самом деле его внутренняя логика очень проста, просто взгляд вниз с верхнего слоя.

Автоматически сгенерированный код позиционирования выглядит следующим образом:

poco("android.widget.LinearLayout").offspring("com.zhihu.android:id/action_bar_root").offspring("com.zhihu.android:id/parent_fragment_content_id").offspring("android.support.v7.widget.RecyclerView").child("android.widget.LinearLayout")[0]

В этом автоматически сгенерированном коде таргетинга мы видимoffspring,childоба метода. вchildпредставляет дочерний узел,offspringПредставляет внучатый узел, дочерний узел внучатого узла, внучатый узел внучатого узла... . Короче говоря, используйтеchildбудет искать только желаемый контент в дочерних узлах и использоватьoffspringВсе узлы в нем будут пройдены один раз, как папка, рекурсивно, пока не будет найден атрибут, удовлетворяющий условиям. Очевидно, потомство будет медленнее ребенка.

На самом деле, мы можем немного упростить этот код позиционирования:

poco("com.zhihu.android:id/parent_fragment_content_id").offspring("android.support.v7.widget.RecyclerView").child("android.widget.LinearLayout")[0]

Этот метод упрощения представляет собой ту же логику, что и упрощение из XPath, скопированного из Chrome.Основной принцип заключается в том, чтобы найти «уникальное» значение атрибута, а затем использовать это значение атрибута для поиска.

Поскольку я нажал на первый результат поиска, код таргетинга имеет[0]. Теперь из-за необходимости получать содержимое всех результатов поиска его следует удалить[0]И используйте цикл for для расширения, а затем получите содержимое внутри:

result_obj = poco("com.zhihu.android:id/parent_fragment_content_id").offspring("android.support.v7.widget.RecyclerView").child("android.widget.LinearLayout")
for result in result_obj:
    title = result.child(name='com.zhihu.android:id/magi_title').get_text()
    count = result.child(name='com.zhihu.android:id/magi_count').get_text()
    print(title, count)

Эффект операции показан на рисунке ниже.

Управление несколькими телефонами

Когда мы подключаем несколько телефонов Android к компьютеру, выполняем команду:

adb devices -l

Эффект операции показан на рисунке ниже.

Каждый телефон будет указан. Крайний слева номер — это серийный номер мобильного телефона. Используйте этот серийный номер, чтобы указать несколько мобильных телефонов:

from airtest.core.api import auto_setup
from airtest.core.android import Android
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
auto_setup(__file__)

device_1 = Android('76efadf3a7ce4')
device_2 = Android('adfasdfasf23')
device_3 = Android('adifu39ernla')

poco_1 = AndroidUiautomationPoco(device_1, use_airtest_input=True, screenshot_each_action=False)
poco_2 = AndroidUiautomationPoco(device_2, use_airtest_input=True, screenshot_each_action=False)
poco_3 = AndroidUiautomationPoco(device_3, use_airtest_input=True, screenshot_each_action=False)

Таким образом, использование USB-концентратора на одном компьютере и подключение двадцати или тридцати мобильных телефонов совершенно не проблема.

беспроводной режим

Airtest поддерживает беспроводной режим, не требует USB, пока компьютер и мобильный телефон подключены к одному и тому же WIFI, им можно управлять:

Если вас интересует, как включить беспроводной режим, оставьте сообщение, и я продолжу писать.

Создайте кластер мобильных сканеров

Один компьютер может быть подключен к 30 мобильным телефонам, поэтому, если есть много компьютеров и много мобильных телефонов, можно реализовать кластер сканера мобильных телефонов, и эффект работы показан на следующем рисунке.

Вопрос о том, как построить кластер поисковых роботов, выходит за рамки этой статьи. Если вам интересно, вы можете прочитать мою книгу:Разработка поискового робота Python от входа до реального бояГлава 10 содержит подробные инструкции и меры предосторожности по созданию мобильного кластера поисковых роботов.

Если вас заинтересовала моя книга, подпишитесь на мою общедоступную учетную запись WeChat, чтобы общаться со мной.