本章将对拼多多APP端进行自动化爬虫,由于发现现在的文章对APP爬虫的介绍少之又少,因此本文也会详细地介绍APP自动化工具库uiautomator2和辅助工具weditor。
注意:
- 本文将默认已经配置了abd、ATX以及一系列必要的设备,下午只讲思路以及实现方法,并没有介绍到如何按照测试环境,若有需要将于日后发布环境配置的文章。
1、启动Weditor
执行weditor:命令行运行python -m weditor
随后将会自动打开一个网页,即我们的辅助工具
网页上的任何元素都可以通过左侧点击方式得到它所在位置的Hierarchy(类似于web的xpath)
2、python利用uiautomator2库连接上设备
由于uiautomator库的操作非常简单,这里就不赘述了,设置连接方式和连接以及要采集的商品数量:
class PDD:
def __init__(self, shop, devices, account):
"""
初始化PDD类,连接到设备并设置店铺名称。
:param shop: 店铺名称
:param devices: 设备的IP地址或序列号
:param account: 要获取的商品数量
"""
self.shop_name = shop
self.device = u2.connect(devices) #连接上手机并返回给debvice
self.account = account
3、对pdd数据进行搜索和采集
3.1搜索进入商品界面
这里我们先观察pdd界面,观察它搜索框的位置,可以看到它的定位有text,resourceld的方式,但由于text情况并不稳定,因此我们采用resourceId的定位方式,点击搜索框元素
pdd这里需要点击搜索后跳到下一页面后才能继续输入,之后要输入商品名称并且点击搜索按钮。因此从界面到搜索的方法可以这么写
def __search(self):
"""
在设备上执行搜索操作。
"""
self.device(resourceId='com.xunmeng.pinduoduo:id/pdd').click()
self.device.send_keys(self.shop_name)
self.device(text='搜索').click()
time.sleep(1)
运行代码后的页面为:
这里可以看到我们已经点入进来了
3.2循环点击商品进入详情页
接下来我们该对商品进行点击,进入到特定的商品详情页后。会发现每一个模块的的位置,因此在原理上可以通过模块定位。由于手机页面仅能显示6个,所以android.widget.FrameLayout这个元素也只有6个。
理论上可以用这个方法来定位到块元素,并且通过点击的方式进入到商品的详情页。但是并不是很推荐,一:速度太慢。二:容易重复点击。因此我们采用关键字的方式来定位元素的位置(类似于网页端的//*[contains(text(), '文本内容')]。
这里我们采用定位¥这个符号,因此该符号每一个页面都有,并且为了预防会出现重复点击的事件发生,我们讲元素定位到价格,采用定位¥元素的兄弟节点,并且记录兄弟节点的方式,以此达到不会重复点击的目的
但点击进入页面之后,为了表现出循环的方式,因此还添加点击返回的操作。以下是便利点击的代码:
def __slide(self):
"""
滑动浏览页面,并获取符合条件的商品详细信息。
"""
temp_account = 0
recent_elements = []
while 1:
elems = self.device.xpath('//*[contains(@text, "¥")]/following-sibling::*[1]').all()
for elem in elems:
if elem.text and elem.text not in recent_elements:
if len(recent_elements) >= 3:
recent_elements.pop(0) # 移除最早添加的元素
recent_elements.append(elem.text)
elem.click()
#操作
self.get_detail()
# 返回到上一级页面
self.device.xpath(
'//*[@content-desc="顶部工具栏"]/android.widget.RelativeLayout[1]/android.widget.FrameLayout[1]').click()
if temp_account > self.account:
return recent_elements
print(recent_elements)
temp_account += 1 # 将该行移动到这里,确保每次处理都会增加计数器
self.device.swipe_ext("up", 0.5)
print('next')
time.sleep(3)
3.3获取商品信息(配合3.2实现循环获取)
进行了点击之后,我们讲进入如下的界面:
为了能够采集到数据,我们也采用Ui定位的方式来得到指定的元素内容(方式如上述一样,这里就不赘述了,直接显示代码),这里我们抓取了商品的价格,标题以及店铺名称
def __get_detail(self):
"""
获取商品的详细信息,包括价格、标题和店名。
:return: 包含商品详细信息的字典
"""
detail = {}
# 获取价格
price = ''
price_elements = self.device.xpath(
'//*[@resource-id="android:id/content"]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]/android.widget.LinearLayout[2]').child(
'//*').all()
for elem in price_elements:
if elem.text:
price += elem.text
detail['price'] = price
# 获取标题
title_elements = self.device.xpath(
'//android.support.v7.widget.RecyclerView/android.widget.LinearLayout[3]/android.widget.FrameLayout[1]/android.view.ViewGroup[1]').child(
'//android.widget.TextView').all()
real_title = ''.join([elem.text for elem in title_elements if elem.text])
detail['real_title'] = real_title
# 向上滑动页面以获取更多内容
self.device.swipe_ext("up", 1)
# 获取店名
store = ''
store_name_elements = self.device.xpath(
'//*[@resource-id="android:id/content"]/android.widget.FrameLayout[1]/android.support.v7.widget.RecyclerView[1]').child(
'//*').all()
for elem in store_name_elements:
if '专营店' in elem.text or '旗舰店' in elem.text:
store = elem.text
detail['store'] = store
return detail
4、运行结果:
这里我们抓取了商品价格,商品标题以及店铺名称的元素
需要源码请私信我
ILDD