大家好,欢迎来到IT知识分享网。
APP爬取思路和方案选择
思路一
通过抓包软件对APP进行抓包分析, 这种方式可以看到 App 在运行过程中发生的所有请求和响应。得知接口之后可以通过设置合适的请求头和各种参数来发送HTTP或者HTTPS请求接口,接口返回的数据就是想要数据了。
这种方式一旦实现,基本上算是一劳永逸的,除非接口和返回数据定义发生变化。但是如果一些动态参数设置不对,访问接口则不能得到任何数据,换句话说,只要无法激活成功教程参数,这条路就是死路一条。
思路二
通过自动化测试工具模拟手工操作APP进行数据的爬取。通过向自动化测试工具(例如Appium)发送操作指令,驱动设备完成点击、输入、滑动等各种操作,分析页面数据完成数据爬取。
这种方式相比于方式一而言,并不会受限于请求头和动态参数,只要是人工可以操作的,自动化测试工具都可以帮助我们进行完成,而所有的APP的所有功能所有页面用户都可以进行操作,意味着APP内所有的数据都可以拿到。
方案选择
本人在尝试使用方式一的过程中,抓包分析接口之后发现有些动态参数无法搞定,故放弃该方式。采用方式二进行爬取。
爬取核心
Appium启动APP
使用Appium启动APP时需要配置参数:platformName、deviceName、appPackage、appActivity。配置完成之后Appium会自动查找手机上面的包名和入口类,然后将其启动。
platformName:平台名称,本文使用的是安卓平台,填写Android。 deviceName:设备名称。 appPackage:APP程序包。 appActivity:程序入口。
- 获取appPackage和appActivity的方法:
最简单有效的方法为使用命令行获取。使用Appium客户端连接到APP,将APP打开到需要获取appActivity的页面,执行下面命令:
adb shell dumpsys activity | grep mFocusedActivity
代码如下:
def __init__(self): print("init") self.desired_caps = { "platformName": "Android", "deviceName": "127.0.0.1:62001", 'platformVersion': '5.1', "appPackage": "com.luojilab.player", "appActivity": "com.luojilab.business.HomeTabActivity", # 主页 "noReset": True } self.driver = webdriver.Remote(DRIVER_SERVER, self.desired_caps) self.wait = WebDriverWait(self.driver, TIMEOUT)
这段代码的作用是使用Appium启动得到APP并进入主页。如图:
点击“课程”按钮进入课程页
本文目的是爬取课程的数据,所以需要点击课程进入课程页。人的操作是这样的的,首先在课程页面找到课程按钮,然后点击。程序的操作也是一样的:首先要定位到“课程”这个按钮,然后进行点击。
使用Appium定位元素
点击选中左边“课程”按钮,可以看到这个元素的源代码,通过xpath定位:
course = self.driver.find_element_by_xpath("//android.widget.TextView[@text='课程']") # 课程
Appium可以进行点击的操作。点击课程按钮的代码如下:course.click()
定义课程数据类
课程页面如图所示:
从课程页面可以看到,一门课程展现出来的数据有:课程名称、课程摘要、作者姓名和头衔、单价以及销量。
从面向对象的思想来说,课程就是一个对象,这个对象有如下属性:课程名称、课程摘要、作者姓名和头衔、单价以及销量。用代码表示就是这样的:
class CourseData(object): def __init__(self, course_name, summary, lecturer_name_and_title, price, subscribe_num): super().__init__() self.course_name = course_name self.summary = summary self.lecturer_name_and_title = lecturer_name_and_title self.price = price self.subscribe_num = subscribe_num
获取所有课程数据
通过Appium分析页面的源代码,可以很容易解析得到课程的各种数据。
代码如下:
course_names = temp.find_element_by_id('com.luojilab.player:id/column_name') #课程名称 summaries = temp.find_element_by_id('com.luojilab.player:id/summary') # 摘要 lecturer_name_and_titles = temp.find_element_by_id( 'com.luojilab.player:id/tv_name_and_title') # 讲师 prices = temp.find_element_by_id('com.luojilab.player:id/price') #价格 subscribe_nums = temp.find_element_by_id('com.luojilab.player:id/tv_subscribe_num') # 价格
当获取完一屏的数据,需要向上滑动继续获取数据。
Appium滑动API说明:
方法:swipe(int start x,int start y,int end x,int y,duration) 参数说明: int start x:开始滑动的x坐标; int start y:开始滑动的y坐标 ; int end x:结束点x坐标; int end y:结束点y坐标; duration:滑动时间。
本文是从屏幕下部滑动到屏幕上部,滑动时间为2000ms。具体代码为:
self.driver.swipe(FLICK_START_X, FLICK_START_Y, FLICK_START_X, FLICK_START_Y + FLICK_DISTANCE, 2000)
当无法滑动的时候,数据就获取完成了。
课程数据写入Excel
数据获取完成之后需要进行存储。Python中有专门操作Excel的库:openpyxl。本文使用openpyxl将爬取到的数据写入Excel进行保存。核心代码如下:
# 定义数据输出的Excel try: wb = openpyxl.load_workbook(PATH) except: wb = openpyxl.Workbook() # wb = openpyxl.Workbook() sheet_name = time.strftime("%F") sheet = wb.create_sheet(sheet_name) row = ["学院", "课程名称", "课程摘要", "主讲人", "单价", "销量", "销售金额"] sheet.append(row) ... wb.save(PATH)
完整代码
import openpyxl from appium import webdriver import time from selenium.webdriver.support.wait import WebDriverWait from config import DRIVER_SERVER, TIMEOUT, FLICK_START_X, FLICK_DISTANCE, FLICK_START_Y, PATH class CourseData(object): def __init__(self, course_name, summary, lecturer_name_and_title, price, subscribe_num): super().__init__() self.course_name = course_name self.summary = summary self.lecturer_name_and_title = lecturer_name_and_title self.price = price self.subscribe_num = subscribe_num def __eq__(self, other): if self.course_name != other.course_name: return False if self.summary != other.summary: return False if self.lecturer_name_and_title != other.lecturer_name_and_title: return False if self.price != other.price: return False if self.subscribe_num != other.subscribe_num: return False return True class Action(): def __init__(self): print("init") self.desired_caps = { "platformName": "Android", "deviceName": "127.0.0.1:62001", 'platformVersion': '5.1', "appPackage": "com.luojilab.player", "appActivity": "com.luojilab.business.HomeTabActivity", # 主页 "noReset": True } self.driver = webdriver.Remote(DRIVER_SERVER, self.desired_caps) self.wait = WebDriverWait(self.driver, TIMEOUT) def entry(self): college_list = ["商学院", "能力学院", "视野学院", "人文社科", "科学学院"] wait = WebDriverWait(self.driver, 20) # 同意隐私条款 print("agree") btn_aggree = self.driver.find_elements_by_id('com.luojilab.player:id/btn_agree') if btn_aggree != []: btn_aggree[0].click() # 定义数据输出的Excel try: wb = openpyxl.load_workbook(PATH) except: wb = openpyxl.Workbook() # wb = openpyxl.Workbook() sheet_name = time.strftime("%F") sheet = wb.create_sheet(sheet_name) row = ["学院", "课程名称", "课程摘要", "主讲人", "单价", "销量", "销售金额"] sheet.append(row) sheet.column_dimensions['A'].width = 15 # 学院 sheet.column_dimensions['B'].width = 40 # 标题 sheet.column_dimensions['C'].width = 40 # 摘要 sheet.column_dimensions['D'].width = 40 # 作者 sheet.column_dimensions['E'].width = 15 # 单价 sheet.column_dimensions['F'].width = 15 # 销量 sheet.column_dimensions['G'].width = 15 # 销售金额 for col in college_list: print("enter course...") time.sleep(1) course = self.driver.find_element_by_xpath("//android.widget.TextView[@text='课程']") # 课程 course.click() print("get college...") time.sleep(1) colleges = self.driver.find_element_by_id( 'com.luojilab.player:id/college_filter_list').find_elements_by_xpath( '//android.widget.TextView') for college in colleges: print(college.text) if col in college.text: print(col, "click") shang_course_names = [] shang_summaries = [] shang_lecturer_name_and_titles = [] shang_prices = [] shang_subscribe_nums = [] college.click() while True: time.sleep(2) temps = self.driver.find_element_by_id('com.luojilab.player:id/rv').find_elements_by_class_name( 'android.widget.RelativeLayout') for temp in temps: try: course_names = temp.find_element_by_id('com.luojilab.player:id/column_name') summaries = temp.find_element_by_id('com.luojilab.player:id/summary') lecturer_name_and_titles = temp.find_element_by_id( 'com.luojilab.player:id/tv_name_and_title') prices = temp.find_element_by_id('com.luojilab.player:id/price') subscribe_nums = temp.find_element_by_id('com.luojilab.player:id/tv_subscribe_num') except Exception as e: continue shang_course_names.append(course_names.text) shang_summaries.append(summaries.text) shang_lecturer_name_and_titles.append(lecturer_name_and_titles.text) shang_prices.append(prices.text) shang_subscribe_nums.append(subscribe_nums.text) if temps[-1].find_elements_by_id('com.luojilab.player:id/rx_loadmore_text') != []: break else: self.driver.swipe(FLICK_START_X, FLICK_START_Y, FLICK_START_X, FLICK_START_Y + FLICK_DISTANCE, 2000) print(len(shang_course_names), shang_course_names) print(len(shang_summaries), shang_summaries) print(len(shang_lecturer_name_and_titles), shang_lecturer_name_and_titles) print(len(shang_prices), shang_prices) print(len(shang_subscribe_nums), shang_prices) course_data_list = [] if len(shang_course_names) == len(shang_summaries) and len(shang_course_names) == len( shang_lecturer_name_and_titles) and len(shang_course_names) == len(shang_prices) and len( shang_course_names) == len(shang_subscribe_nums): for i in range(len(shang_course_names)): course_data = CourseData(shang_course_names[i], shang_summaries[i], shang_lecturer_name_and_titles[i], shang_prices[i], shang_subscribe_nums[i]) if course_data not in course_data_list: course_data_list.append(course_data) print(len(course_data_list)) for i in range(len(course_data_list)): print(course_data_list[i].course_name, "-", course_data_list[i].summary, "-", course_data_list[i].lecturer_name_and_title, "-", course_data_list[i].price, "-", course_data_list[i].subscribe_num) time.sleep(0.1) # 写入Excel cell_price = course_data_list[i].price[course_data_list[i].price.strip().find("¥") + 2:] cell_subscribe_num = int( course_data_list[i].subscribe_num[:course_data_list[i].subscribe_num.strip().find("人")]) row = [col, course_data_list[i].course_name, course_data_list[i].summary, course_data_list[i].lecturer_name_and_title, cell_price, cell_subscribe_num, float(cell_price) * cell_subscribe_num] sheet.append(row) wb.save(PATH) break btn_back = self.driver.find_elements_by_id('com.luojilab.player:id/iv_back_btn') if btn_back != []: btn_back[0].click() if __name__ == '__main__': action = Action() action.entry()
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/50558.html