启发式爬虫

简而言之启发式爬虫是基于所有历史经验及曾经看到过的已知场景,通过分析这些场景和利用已知的经验构造并实现规则的爬虫。

  1. 什么是启发式爬虫?
  2. 启发式爬虫好处
  3. 启发式爬虫具体实现

什么是启发式爬虫?

  简而言之启发式爬虫是基于所有历史经验及曾经看到过的已知场景,通过分析这些场景和利用已知的经验构造并实现规则的爬虫。

启发式爬虫好处

现今网站特征:    

1. Vue.js
2. JQuery
3. Handlebars
4. 代码混淆反爬虫
5. DOM时间频繁更新    

  这些网站特征导致requests、urllib这些传统爬虫所用到的模块爬取不到有用的信息。这样,基于无界面的浏览器横空出世。

  无界面浏览器发展到现在,Chromium Headless可以说是众多浏览器中的佼佼者,一方面它是谷歌研发市场第一,几个小时一个版本更新,另一方面,Chromium Headless积极支持W3C标志组织。这些优势,势必会成为将来爬虫和自动化测试的利器。

  既然已经拥有了这么强大的无界面浏览器,就要用强大的工具去操纵它,puppteer翻译是操纵木偶的人,利用这个工具,我们能做到一个操纵页面的人。puppteer是一个Node.js的库,支持调用Chrome的Api来操纵web,相比较Selenium或是PhantomJs,它最大的特点就是它的操作Dom可以完成在内存中进行模拟既在V8引擎中处理而不打开浏览器,而且关键是这个是Chrome团队在维护,会拥有更好的兼容性和前景。

  Pyppteer是python中操作Chromium Headless的库,具有个puppteer一样的功能,如以下功能:

1. 利用网页生成PDF、图片
2. 爬取SPA应用,并生成预渲染内容(即“SSR” 服务端渲染)
3. 可以从网站抓取内容
4. 自动化表单提交、UI测试、键盘输入等
5. 帮你创建一个最新的自动化测试环境(chrome),可以直接在此运行测试用例
6. 捕获站点的时间线,以便追踪你的网站,帮助分析网站性能问题

启发式爬虫具体实现

  首先可以把爬虫看作一个工厂流水线系统,流水线系统一定会有一个总队长负责各条生产线任务调度,在这里ROP就是总队长。流程明确后,每个步骤都各司其职实现各自的功能。    

  爬虫总队长这个管理器的功能负责任务调度和事件管理。在做扫描器爬虫的第一步先将URL传给任务调度器总队长,总队长把这个任务传给下面,之后打开页面进入到加载状态。页面加载后需要判断当前页面是否完全,比如有时候某些网页服务器网络性差,或是遇到GS报错、网站超时某些资源显示不全,这时候可以通过下图标注的三个状态来确定整个网页的结构是否加载完成,整个页面是否打开完成。

启发式爬虫具体实现

  完成后把整个浏览器page页面锁定不做任何动作,让它打开另外一个新网页,或者跳转其他网页上去。

  当整个网页加载好之后,把整个网页跳转锁定后就可以进入到函数劫持阶段。随后开始注入一个监听器,监听所有事件的变动和事件触发的信息。当文件加载、函数劫持、监听都完成之后,可以编译出任何输入框绑定的事件,对某个输入参数值进行常规判断的一些信息。

  当我们发现页面存在表单的时候,可以通过分析表单的输入类型以及表单名称,进行一些参数填充。上面所有流程结束后,会得到当前页面所有信息的结果题。此时可以通过去虫过滤之后,返回给事件管理器,重复执行整个流程。

  确定总体流程之后回到刚才的第一步,页面加载,录入实现。

  当一个页面加载完成之后,应该在什么时候注入我们的劫持代码,这里边有状态可以选择。第一个在page load之后;第二个是等待页面加载完成之后,也就是当前网络状态全部空闲的时候,整个爬虫执行流再继续执行;或者判断整个网页的DOM树是否被加载并解析完成。

演示实例

Example: open web page and take a screenshot.

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch()
    page = await browser.newPage()
    await page.goto('http://example.com')
    await page.screenshot({'path': 'example.png'})
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())

Example: evaluate script on the page.

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch()
    page = await browser.newPage()
    await page.goto('http://example.com')
    await page.screenshot({'path': 'example.png'})

    dimensions = await page.evaluate('''() => {
        return {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight,
            deviceScaleFactor: window.devicePixelRatio,
        }
    }''')

    print(dimensions)
    # >>> {'width': 800, 'height': 600, 'deviceScaleFactor': 1}
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())