Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

动态爬虫(二) #108

Open
PyxYuYu opened this issue May 4, 2017 · 1 comment
Open

动态爬虫(二) #108

PyxYuYu opened this issue May 4, 2017 · 1 comment
Labels

Comments

@PyxYuYu
Copy link
Owner

PyxYuYu commented May 4, 2017

No matter how far you may fly, never forget where you come from.

0x01 动态爬虫

  • 动态爬虫
    • 页面加载完成后,通过 Ajax 加载数据,需要 用户交互(点击、滚动等)加载数据,这些情况下就需要动态爬虫
    • 模拟用户交互:用户交互的本质,实际上就是触发了绑定在 DOM 节点的事件,所以模拟用户操作就是触发节点事件
    • 爬虫分析
      • 是否添加了新的节点(<a><iframe> 等)
      • 是否发起了新的请求(Ajax 请求跳转 等)
    • 爬虫实现
      • 获取绑定事件
        • JavaScript 中绑定事件,都会调用 addEventListener 函数,在页面代码执行前 HOOK addEventListener 函数就可以捕获到哪些 DOM 节点绑定了事件
        • 除了 addEventListener 绑定事件,还有一些 inline-script 是无法通过 HOOK addEventListener 来获取,如
          • <div id='ll' onclick="alert('dd')"></div>
      • 触发事件
        • JavaScript 中提供 dispatchEvent 函数,可以触发指定 DOM 节点的指定事件
        • onXXXX 属性可以通过遍历节点来触发
      • 获取触发事件的结果
        • 监听 DOMNodeInserted 事件来检查页面中的 DOM 是否发生变化
        • Ajax 请求的捕获
          • onResourceRequested 可以捕获非主流框架的请求,但需要通过正则匹配筛选出有效请求
          • XMLHttpRequest.openXMLHttpRequest.send 可以准确的捕获请求内容
    • 爬虫流程
      • 页面加载前,HOOK 三个接口:addEventListenerXMLHttpRequest.openXMLHttpRequest.send
      • 页面加载完后,获取所有的 <a><iframe><form> 标签,开启页面 DOM 节点监听,并触发所有的事件,最后输出结果
    • 爬虫Tips
      • 自动填写表单:应对某些情况下参数为空导致表单无法提交
      • 禁止非必要资源的加载:jpg、png、css、mp4
      • 页面加载完成后禁止跳转:防止因为触发事件导致的跳转
      • HOOK 会导致页面阻塞的函数:alertprompt
      • 触发事件向下冒泡:解决一些不标准的前端代码绑定的 DOM 节点太宽泛导致的问题,非常影响效率
  • PhantomJS
    • JavaScript 动态解析
      • PhantomJS 打开 URL 时就会利用自己的 Webkit 内核去执行 JavaScript
    • HOOK 所有的网络请求
      • PhantomJS 利用 page.onResourceRequested 方法来 HOOK 所有的网络请求
    • 静态页面分析和自动表单分析
      • PhantomJS 利用 page.evaluate 解析 JavaScript,这个执行是 沙盒式 的,它不会去执行网页外的 JavaScript 代码
    • 用户交互
      • 定义两个数组,一个用于存放分析到的链接,一个存放页面中的交互事件
      • 定义两个函数,一个获取页面全部链接,一个获取页面全部交互事件
      • 遍历所有的交互事件,每执行一个交互事件,再获取一次页面全部链接和交互事件(做去重检测)
      • 注:每执行一个交互事件,然后再获取一次页面全部链接和交互事件之前,需要等待几秒,因为如果该交互事件为 Ajax 的请求,它需要等得到服务器返回数据以后,才继续渲染页面
    • Python
      • bin 中的 phantomjs.exe 移至 python27 文件夹中的 Scripts 中就可以在 Python 代码中调用
      • 利用 Selenium 中的 webdriver 打开 PhantomJS 浏览器
         #!/usr/bin/env python
         # coding=utf-8
         
         from selenium import webdriver
         
         # 打开 PhantomJS 浏览器
         driver = webdriver.PhantomJS()
         driver.get('http://www.baidu.com')
         data = driver.page_source
         print data
         driver.quit()
      
      • 利用 driver.get 方法打开请求的 URLwebdriver 会等待页面完全加载完成之后才会返回,即程序会等待页面的所有内容加载完成,JS 渲染完毕之后才继续往下执行
        • 注:如果这里用到许多 Ajax,程序可能无法知晓是否已经完全加载完毕
      • webdriver 提供了许多寻找网页元素的方法,比如 find_element_by_* 等,也可以再加载完成后,利用 BeautifulSoup 来分析
         #!/usr/bin/env python
         # coding=utf-8
         
         from bs4 import BeautifulSoup
         from selenium import webdriver
         import time
         
         driver = webdriver.PhantomJS()
         driver.get('http://www.baidu.com')
         time.sleep(3)
         data = driver.page_source
         soup = BeautifulSoup(data, 'html.parser', from_encoding='utf-8')
         temp = html_parse.find_all('a')
         print temp
         driver.quit()
      
  • Chrome
    • headless 支持命令行下工作,看来 PhantomJS 很快就会被替代了
@PyxYuYu PyxYuYu added the Spider label May 4, 2017
@Karl3Kk
Copy link

Karl3Kk commented Jun 27, 2018

最近在研究动态的爬虫,请问,如何在页面加载前,HOOK 这些接口呢(addEventListener、XMLHttpRequest.open、XMLHttpRequest.send)? 使用的是chrome headless +pyppeteer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants