爬虫爬虫Pyspider+Selenium+Chrome

前言:

最近受林老板之托需要爬取一些数据。想要简单实现,看到Pyspider好像不错,好的,就决定是你拉。

Pyspider介绍:http://www.pyspider.cn/,网上使用方法教程很多,不再细说。

 

分析:

这次需要爬取的任务大致情况如下:

  1. 需要爬取某网站试题以及答案

  2. 试题以及答案最终会在同一个页面上呈现

  3. 每次显示有限的题数,例如20道题目,做完提交后可以看答案

  4. 需要进行答案填写和提交,下次进入才会有新的题目出来

  5. 该网站最终链接是js异步请求生成的

我需要的爬取流程也很简单:

  1. 手工通过账号密码登录该网站,获取登录后的cookies信息

  2. 脚本通过cookies登录该网站

  3. 一路跳转到试题界面

  4. 填写试题,提交,查看题目和答案

  5. 解析html,将试题和答案保存到本地

 

搞起:

虽然流程是按部就班的来,但是为了兴趣和成效,我先从最后一步走起(当然cookies登录必不可少):

百度了Pyspider的用法和PyQuery的用法,这里提供两个链接参考:

  1. http://www.pyspider.cn/book/self.crawl-16.html

  2. https://www.cnblogs.com/lei0213/p/7676254.html

很快就最终结果给弄出来了。输入试题和答案页面的链接,就会生成结果文件,一切顺利,果然信心满满(^_^)。

 

遇到问题:

然后是自动进行爬取的跳转操作:

Pyspider已经支持了PhantomJS,所以要渲染带js的页面,或者实现点击操作都可以。

Pyspider的模拟点击是通过crawl的参数js_script实现的,例如:

self.crawl('http://www.example.org/', callback=self.callback,fetch_type='js', js_script='''

               function() {

                   document.querySelectorAll('.btn-inner')[1].click();

               }

               ''')

但是对于我需要爬取的网页却不行,听说PhantomJS存在假死情况,说法根据百度到有人的问题:https://segmentfault.com/q/1010000007814470/a-1020000007838103。

Pyspider的一般做法是获取点击跳转的URL,然后再进行crawl。

但是面对一些通过js跳转的网页,除非你能解析出点击后的js如何返回链接,由于js通常加密过,有一定难度,而且这样工作量太大了。

 

临时解决方法:

但老板那边催着要,先爬到要紧,想到了使用按键精灵获取最终页面的链接。

我使用的按键精灵:http://www.anjian.com/download.htm,使用很简单,想必一看就会,(ps:按键精灵用于玩网游也是不错的)

录制鼠标和键盘事件:

  1. 点击进入首页,从首页点击进入试题

  2. 进行提交,进入试题和答案页

  3. 复制页面链接

  4. 粘贴到Pyspider代码中

  5. 点击调试的run按钮

不断重复这个脚本,数据就爬下来了。

这个方法虽然简单,但是主要缺点也是很明显:

  1. 按键脚本难以重复使用,因为脚本的鼠标操作坐标是根据屏幕的,它根本不知道网页

  2. 不能后台进行,这台电脑就不能做其他事情了

  3. 效率慢

 

完善:

百度搜到参考文章:Pyspider使用Selenium+Chrome实现爬取js动态页面  https://www.jianshu.com/p/8d955deac99b ,也很简单,该大神的代码已经贴上,运行就可以了。

我这次需要的步骤也很明了了:

  1. 搭建Flask+Selenium+Chrome的后台服务

  2. 通过该后台服务处理页面模拟点击事件,返回最终页面

  3. Pyspider访问该后台服务,获取最终页面,解析html获取数据

我在文章开头想好的流程1-4都可以在这个后台完成了。

通过Selenium操作浏览器进行页面跳转、填写答案、提交等操作都非常稳健,可以填写答案,代码完成后直接在Pyspider控制台让爬取任务running就可以了,比起按键精灵确实爽多了。

需要注意的是如果这个操作过长,Pyspider可能超时,对于过长的操作可能需要分次操作较好,就是Pyspider中多写几层crawl,后台多处理几次handle_post。

这里贴出我使用的跳转浏览器操作代码作参考,这段代码放在后台selenium_fetcher的handle_post中即可:

# 访问网页

browser.get('https://xxxx')

browser.find_element_by_css_selector("[class='btn btn-primary select-csk']").click()

sleep(1)

browser.find_element_by_css_selector(".sprite.sprite-expand.i-20").click()

sleep(1)

# 进入试题页面

for a in browser.find_elements_by_css_selector("[class='btn btn-round create-exercise']"):

    if '13842' == a.get_attribute("data-keypoint-id"):

        print(a.get_attribute("data-keypoint-id"))

        a.click()

        break



sleep(1)

# 交卷

browser.find_element_by_css_selector(".commit-exercise.last").click()

sleep(1)

try:

    browser.find_element_by_css_selector(".btn.btn-paper.btn-paper-xlarge.submit").click()

except Exception  as e:

    print (e)

sleep(1)

# 进入答案页面

browser.find_element_by_partial_link_text('查看解析').click()

sleep(1)

设置cookies的代码,我的cookies直接在Pyspider中写好了,所以需要获取,然后再设置到selenium的浏览器中:

# 设置cookies
cookie_str = fetch['headers']['Cookies']
if fetch.get('headers') and cookie_str:
    driver.delete_all_cookies()
    for item in cookie_str.split('; '):
        key = item.split('=')[0]
        value = item.split('=')[1]
        print(key+":"+value+'\n')
        driver.add_cookie({'name': key, 'value': value})

遇到的比较印象深刻的问题:

  1. selenium 进行设置cookie时出现 unable set cookie

解决方法:

需要先加载一个页面才能进行add_cookies操作;

add_cookies的参数写法:https://selenium-python.readthedocs.io/api.html#selenium.webdriver.remote.webdriver.WebDriver.add_cookie

  1. pyspider 多层的crawl时,有些页面不爬取

解决方法:

回调方法的age=0。因为如果回调方法有一定时间的话,在时间内不会重复处理相同的url请求。

你可能感兴趣的:(爬虫爬虫Pyspider+Selenium+Chrome)