1,引言

Python网络爬虫内容提取器一文我们详细讲解了核心部件:可插拔的内容提取器类gsExtractor。本文记录了确定gsExtractor的技术路线过程中所做的编程实验。这是第二部分,第一部分实验了用xslt方式一次性提取静态网页内容并转换成xml格式。留下了一个问题:javascript管理的动态内容怎样提取?那么本文就回答这个问题。


2,提取动态内容的技术部件

在上一篇python使用xslt提取网页数据中,要提取的内容是直接从网页的source code里拿到的。但是一些Ajax动态内容是在source code找不到的,就要找合适的程序库把异步或动态加载的内容加载上来,交给本项目的提取器进行提取。

python可以使用selenium执行javascript,selenium可以让浏览器自动加载页面,获取需要的数据。selenium自己不带浏览器,可以使用第三方浏览器如Firefox,Chrome等,也可以使用headless浏览器如PhantomJS在后台执行。

3,源代码和实验过程

假如我们要抓取京东手机页面的手机名称和价格(价格在网页源码是找不到的),如下图:
jd_mobile.jpg


第一步:利用集搜客谋数台的直观标注功能,可以极快速度自动生成一个调试好的抓取规则,其实是一个标准的xslt程序,如下图,把生成的xslt程序拷贝到下面的程序中即可。注意:本文只是记录实验过程,实际系统中,将采用多种方式把xslt程序注入到内容提取器重。
jd_mobile_xslt.jpg


第二步:执行如下代码(在windows10, python3.2下测试通过,源代码下载地址请见文章末尾GitHub),请注意:xslt是一个比较长的字符串,如果删除这个字符串,代码没有几行,足以见得Python之强大
  1. #/usr/bin/python
  2. # 2016.04.29 版本1.0
  3. # 2017.07.29 版本2.0
  4. from urllib import request
  5. from lxml import etree
  6. from selenium import webdriver
  7. import time

  8. # 京东手机商品页面
  9. url = "http://item.jd.com/4325123.html"

  10. # 下面的xslt是通过集搜客的谋数台图形界面自动生成的
  11. xslt_root = etree.XML("""\
  12. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  13. <xsl:template match="/">
  14. <li>
  15. <xsl:apply-templates select="//*[@class='sku-name' and count(././text())>0]" mode="li"/>
  16. </li>
  17. </xsl:template>


  18. <xsl:template match="//*[@class='sku-name' and count(././text())>0]" mode="li">
  19. <item>
  20. <商品名称>
  21. <xsl:value-of select="./text()"/>
  22. </商品名称>
  23. <京东价>
  24. <xsl:value-of select="following-sibling::div[position()=2]//*[@class='p-price']/span[position()=2]/text()"/>
  25. </京东价>
  26. </item>
  27. </xsl:template>
  28. </xsl:stylesheet>""")

  29. # 使用webdriver.PhantomJS
  30. browser = webdriver.PhantomJS(executable_path='C:\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe')
  31. browser.get(url)
  32. time.sleep(3)

  33. transform = etree.XSLT(xslt_root)

  34. # 执行js得到整个dom
  35. html = browser.execute_script("return document.documentElement.outerHTML")
  36. doc = etree.HTML(html)
  37. # 用xslt从dom中提取需要的字段
  38. result_tree = transform(doc)
  39. print(result_tree)
复制代码

第三步:下图可以看到,网页中的手机名称和价格被正确抓取下来了
jd_mobile_result.jpg

4,接下来阅读

至此,我们通过两篇文章演示怎样抓取静态和动态网页内容,都采用了xslt一次性将需要的内容从网页上提取出来,其实xslt是一个比较复杂的程序语言,如果手工编写xslt,那么还不如写成离散的xpath。如果这个xslt不是手工写出来的,而是程序自动生成的,这就有意义了,程序员再也不要花时间编写和调测抓取规则了,这是很费时费力的工作。下一篇《1分钟快速生成用于网页内容提取的xslt》将讲述怎样生成xslt。

5,集搜客GooSeeker开源代码下载源

1. GooSeeker开源Python网络爬虫GitHub源

6,文档修改历史
2016-05-26:V2.0,增补文字说明
2016-05-29:V2.1,增加第五章:源代码下载源,并更换github源的网址




举报 使用道具
| 回复

共 27 个关于本帖的回复 最后回复于 2017-12-1 18:13

Fuller 管理员 发表于 2016-4-29 17:05:33 | 显示全部楼层
原来PhantomJS类似于一个无头浏览器啊,不知道他的适用范围广不广。如果用selenium驱动Firefox或者Chrome的无头浏览器会怎样?是否也很容易用?
举报 使用道具
Fuller 管理员 发表于 2016-5-1 16:04:48 | 显示全部楼层
DS打数机能够自动滚屏、连续动作和模拟点击,不知道这个框架能否实现
举报 使用道具
Fuller 管理员 发表于 2016-5-29 15:23:41 | 显示全部楼层
在简书上看到这么一篇文章《【Python】爬虫技术:(JavaScript渲染)动态页面抓取超级指南》,用Qt web kit库。我很纳闷,这篇文章和上文都是把document变成字符串以后,交给lxml的etree再解析成dom树,然后用xpath或者xslt进行转换。这样岂不多了一道?难道是我理解错了?
PhantomJS为什么要返回outerHTML?为什么不直接用documentElement?
举报 使用道具
zxy0427 初级会员 发表于 2016-5-30 20:39:29 | 显示全部楼层
执行lxml的etree.HTML(), 是把PhantomJS返回的documentElement.outerHTML转换成特定格式的element tree
实测documentElement.outerHTML返回值是整个DOM, 如果取documentElement的返回值,则只拿到下面的这串:
<selenium.webdriver.remote.webelement.WebElement (session="6912b3f0-2663-11e6-9999-b118726d63d1", element=":wdc:1464611912251")>
举报 使用道具
Fuller 管理员 发表于 2016-5-30 21:40:07 | 显示全部楼层
zxy0427 发表于 2016-5-30 20:39
执行lxml的etree.HTML(), 是把PhantomJS返回的documentElement.outerHTML转换成特定格式的element tree
实 ...

Python我是刚刚学,这里我糊涂了,但是我仔细看过DOM国际规范。我有下面的猜测:
1,outerHTML似乎返回的是一个字符串
2,用etree.HTML()把这个字符串转换成了elementtree对象,这个tree对象能用etree的xpath进行定位,那么很可能这个tree对象不是标准的documentElement对象,而是仿DOM的对象结构
3,你的测试结果那么奇怪,会不会是python内部的对象id?
4,如果selenium能够返回一个标准的documentElement对象,那么Python有没有标准的DOM访问接口?比如,getElementsByTag(), getElementById()之类的
5,如果支持标准DOM,是不是就不用转成element tree了?
举报 使用道具
shenzhenwan10 金牌会员 发表于 2016-5-31 13:59:26 | 显示全部楼层
本帖最后由 shenzhenwan10 于 2016-5-31 16:41 编辑

我理解etree.HTML(), etree.XML()这几个方法就是用python的数据结构建立一棵树,用于之后对etree的操作
目前python库实现了xslt提取的只找到了lxml的etree,实现了xpath提取的倒是不少,如BS4, HTML parser
举报 使用道具
shenzhenwan10 金牌会员 发表于 2016-5-31 16:42:50 | 显示全部楼层
如果用selenium.webdriver来直接操作浏览器,那就不用转换了。
比如下面的几行代码:
  1. driver = webdriver.Firefox("C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe")
  2. driver.get("http://passport.baidu.com")
  3. time.sleep(10)
  4. driver.find_element_by_id("TANGRAM__PSP_3__userName").click()
  5. driver.find_element_by_id("TANGRAM__PSP_3__userName").send_keys("dali02310")
复制代码
举报 使用道具
Fuller 管理员 发表于 2016-5-31 23:28:52 | 显示全部楼层
shenzhenwan10 发表于 2016-5-31 16:42
如果用selenium.webdriver来直接操作浏览器,那就不用转换了。
比如下面的几行代码:
...

能否简单解释一下上面这段代码是干什么用的?那个网址是哪里?为什么要这么做?
举报 使用道具
Fuller 管理员 发表于 2016-5-31 23:37:58 | 显示全部楼层
shenzhenwan10 发表于 2016-5-31 13:59
我理解etree.HTML(), etree.XML()这几个方法就是用python的数据结构建立一棵树,用于之后对etree的操作
目 ...

我看到一段别人写的代码,用Qt webkit 的driver,刚才还看到你的跟帖用Firefox的driver。我一直怀疑这样做的能力到底有多强。原因分析如下:

无论用.net编程工具直接操作IE或者Firefox的nsBrowser,还是你这些代码,以及webkit driver,你都可以想象成用一个编程语言操作一个黑盒子,你能控制这个黑盒子的能力局限在这个盒子提供的接口能力。从面向对象技术来说,这种接口协约确保了安全性和一致性,这是来自于“约束”的。

如果另一条路线:我直接进入到这个盒子里面,嵌入我的代码,把这个盒子的其它功能作为我的四肢,我的代码指挥他们,就可以不受接口的约束。GooSeeker网络爬虫DS打数机就是用这个思路做成的,他可以模拟人的任何操作浏览器的行为。

也许是我对python理解不够,权当抛砖引玉
举报 使用道具
您需要登录后才可以回帖 登录 | 立即注册

精彩推荐

  • Gephi社会网络分析-马蜂窝游记文本分词并同
  • Gephi社会网络分析-基于马蜂窝游记文本以词
  • 知乎话题文本根据词语间距筛选后生成共词矩
  • 马蜂窝游记文本分词后以词语间距为筛选条件
  • 学习使用apriori算法挖掘关联关系

热门用户

GMT+8, 2024-3-29 22:28