手机APP商品评论获取,需要获取 昵称,发布日期,商品名称,用户评论等信息,如果用相似元素组获取这些信息,在用户滑动之后,可能会导致评论信息获取错乱,比如用户A对应到用户B发布的评论。

先来看下评论页面的结构,使用【获取手机UI树】指令,获取xml结构的UI树,可以看到在一个手机屏上,最多有5个用户评论框,通过index这个属性可以区分是哪个用户发表的评论。
方法一:
设置一个变量传入index属性中,通过xpath直接定位到同一个用户的昵称,日期和评论。


方法一能实现评论抓取,但是速度会有点慢,实测36条评论大概需要4-5分钟,如果碰到有图的评论,速度就会更慢了。
如何加速?我们先来看看手机自动化的原理。

大家看看这幅图, 包含了 3个主体部分 : 自动化程序、Appium Server、移动设备
自动化程序
自动化程序是由我们来开发的,实现具体的【手机自动化】功能。
要发出具体的指令控制手机,也需要使用客户端库。
我们需要安装好客户端库,调用这些库,就可以发出自动化指令给手机。
Appium Server
Appium Server 是 Appium 组织开发的程序,它负责管理手机自动化环境,并且转发自动化程序的控制指令给手机,并且转发手机给自动化程序的响应消息。
手机设备
当然手机上也包含了我们要自动化控制的手机应用APP。
手机设备为什么能接收并且处理自动化指令呢?
因为,Appium Server 会在手机上安装一个 自动化代理程序, 代理程序会等待自动化指令,并且执行自动化指令。
比如:要模拟用户点击界面按钮,Appium 自动化系统的流程是这样的:
自动化程序调用客户端库相应的函数, 发送 【点击元素】的指令(封装在HTTP消息里)给 Appium Server
Appium Server 再转发这个指令给 手机上的自动化代理
手机上的自动化代理接收到指令后,调用手机平台的自动化库,执行点击操作,返回点击成功的结果给Appium Server
Appium Server 转发给自动化程序
自动化程序了解到本操作成功后,继续后面的自动化流程
了解了手机自动化的原理,可以发现,一条控制手机指令的执行,实际上一连串的请求和响应的过程。这个过程比较耗时。
方法一主要耗时是在定位元素和获取元素信息上,如果我们能减少控制手机指令,就能减少应用运行时间。
方法二:
实际当前手机屏上展示的信息,都在手机UI树中可以获取,所以我们只需要执行【获取手机UI树】这一条指令,然后再去解析UI树中的信息就行。实测下来,29条评论大概1分钟左右。


插入代码段内容:
from lxml import etree
uia_page = etree.XML(page_source.encode('utf-8'))
cur_index = int(loop_index)
user_name_xpath = "//androidx.recyclerview.widget.RecyclerView[@resource-id='com.ss.android.ugc.aweme:id/c_w']/android.widget.LinearLayout[@index={}]//android.widget.TextView[@resource-id='com.ss.android.ugc.aweme:id/da-']/@text".format(cur_index)
user_name = uia_page.xpath(user_name_xpath)[0]
date_xpath = "//androidx.recyclerview.widget.RecyclerView[@resource-id='com.ss.android.ugc.aweme:id/c_w']/android.widget.LinearLayout[@index={}]//android.widget.TextView[@resource-id='com.ss.android.ugc.aweme:id/da4']/@text".format(cur_index)
date_str = uia_page.xpath(date_xpath)[0]
good_name_xpath = "//androidx.recyclerview.widget.RecyclerView[@resource-id='com.ss.android.ugc.aweme:id/c_w']/android.widget.LinearLayout[@index={}]//android.widget.TextView[@resource-id='com.ss.android.ugc.aweme:id/da_']/@text".format(cur_index)
good_name = uia_page.xpath(good_name_xpath)[0]
good_com_xpath = "//androidx.recyclerview.widget.RecyclerView[@resource-id='com.ss.android.ugc.aweme:id/c_w']/android.widget.LinearLayout[@index={}]//android.widget.TextView[@resource-id='com.ss.android.ugc.aweme:id/c9u']/@text".format(cur_index)
good_com = uia_page.xpath(good_com_xpath)[0]