最近在用selenium爬取数据,发现微软也有该方面的测试驱动,看评价还不错,决定来尝试跑跑看。
事件监听
playwright的page对象提供了一个on方法,可以用来监听页面中发生的各个事件,比如close,console,load,request, response等。
看到response没,就是它,如果你爬取的网站数据都是通过ajax响应的,而对应的ajax请求中有加密参数却又解不开时,那你用这个就对了。
response时间可以在每次网络请求得到相应的时候触发,我们可以设置方法获取到对应的response的全部信息。
基础版
1 2 3 4 5 6 7 8 9 10 11 12 13
| from playwright.sync_api import sync_playwright
def on_response(response): print(f'Statue {response.status}: {response.url}')
with sync_playwright() as p: browser = p.chromium.launch(headless=False) page = browser.new_page() page.on('response', on_response) page.goto('https://spa6.scrape.center/') page.wait_for_load_state('networkidle') browser.close()
|
执行便发现我们拿到了该页面加载的所有资源。
升级版
我们发现大多数是无用的,我们只想要拿到指定的ajax响应,那也很好办,比如加载所有电影的ajax链接url包含:/api/movie/,那我们就过滤下这个响应就好了,并且可以通过json()获取到响应的json结果。这样不就可以对这批数据进行入库了?
1 2 3 4 5 6 7 8 9 10 11 12 13
| from playwright.sync_api import sync_playwright
def on_response(response): if '/api/movie/' in response.url and response.status == 200: print(response.json())
with sync_playwright() as p: browser = p.chromium.launch(headless=False) page = browser.new_page() page.on('response', on_response) page.goto('https://spa6.scrape.center/') page.wait_for_load_state('networkidle') browser.close()
|
进阶版
通常我们爬取的url不止一个,url肯定是动态的,page.on(‘response’, on_response)这样传给回调函数函数只能拿到响应,却不知道是哪个url请求来的,我们想在拿到响应的时候同时能接收到其他的动态参数该如何办呢?
答对了,我们使用匿名函数转发下既可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| from playwright.sync_api import sync_playwright
def on_response(response, url): if '/api/movie/' in response.url and response.status == 200: print("%s得到的响应为:" %url, response.json())
with sync_playwright() as p: browser = p.chromium.launch(headless=False) page = browser.new_page() url = 'https://spa6.scrape.center/' page.on('response', lambda response: on_response(response, url)) page.goto(url) page.wait_for_load_state('networkidle') browser.close()
|
以上不是将参数成功传进去了吗,这样入库时特别是有关联表的时候就能做到一个很好地关联呢。
下拉加载
这个纯粹是题外话,只是简单记录下。
如项目中有以下场景:数据是通过下拉滚动条ajax动态加载的数据,那么问题来了,如果页面较大或者网络不好使,你的下拉根本没有生效,一直处于原地下拉的状态,数据没有被成功请求出来,表现形式为状态一直处于“加载中……”,总不能因为这个一直等着吧。
我这里采取的方式为获取数据项的总数,连续执行了5次页面下拉动作数据项的总数都一样,则证明卡这儿了,就跳过该页面爬取下一个页面了,分析来看里面还是存在一个小的算法的。
首先我们存取最近5次的数据项总数;其次判断5次全部一致才证明卡住了。我们这里相当于模拟了一下队列,先进先出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| items_list = [] while True: if len(set(items_list))==1: return item_sum = get(items) if len(items_list)>4: items_list.pop() items_list.insert(0, item_sum) scroll_down()
|
您有什么更好的解决方案,欢迎指教。