1,引言

在Python网络爬虫内容提取器一文我们详细讲解了核心部件:可插拔的内容提取器类gsExtractor。本文记录了确定gsExtractor的技术路线过程中所做的编程实验。这是第一部分,实验了用xslt方式一次性提取静态网页内容并转换成xml格式。

2,用lxml库实现网页内容提取

lxml是python的一个库,可以迅速、灵活地处理 XML。它支持 XML Path Language (XPath) 和 Extensible Stylesheet Language Transformation (XSLT),并且实现了常见的 ElementTree API。

这2天测试了在python中通过xslt来提取网页内容,记录如下:

2.1,抓取目标

假设要提取集搜客官网旧版论坛的帖子标题和回复数,如下图,要把整个列表提取出来,存成xml格式

2.2,源代码1:只抓当前页,结果显示在控制台

Python的优势是用很少量代码就能解决一个问题,请注意下面的代码看起来很长,其实python函数调用没有几个,大篇幅被一个xslt脚本占去了,在这段代码中,只是一个好长的字符串而已,至于为什么选择xslt,而不是离散的xpath或者让人挠头的正则表达式,请参看《Python即时网络爬虫项目启动说明》,我们期望通过这个架构,把程序员的时间节省下来一大半。

可以拷贝运行下面的代码(在windows10, python3.2下测试通过):

  1. from urllib import request
  2. from lxml import etree
  3. url="http://www.sina.com/cn/forum/7" #由于博客园的限制,如果你要运行该段代码的话请将‘sina’替换成‘gooseeker’
  4. conn=request.urlopen(url)
  5.  
  6. doc = etree.HTML(conn.read())
  7.  
  8. xslt_root = etree.XML("""\
  9. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  10. <xsl:template match="/">
  11. <列表>
  12. <xsl:apply-templates select="//*[@id='forum' and count(./table/tbody/tr[position()>=1 and count(.//*[@class='topic']/a/text())>0])>0]" mode="列表"/>
  13. </列表>
  14. </xsl:template>
  15.  
  16. <xsl:template match="table/tbody/tr[position()>=1]" mode="list">
  17. <item>
  18. <标题>
  19. <xsl:value-of select="*//*[@class='topic']/a/text()"/>
  20. <xsl:value-of select="*[@class='topic']/a/text()"/>
  21. <xsl:if test="@class='topic'">
  22. <xsl:value-of select="a/text()"/>
  23. </xsl:if>
  24. </标题>
  25. <回复数>
  26. <xsl:value-of select="*//*[@class='replies']/text()"/>
  27. <xsl:value-of select="*[@class='replies']/text()"/>
  28. <xsl:if test="@class='replies'">
  29. <xsl:value-of select="text()"/>
  30. </xsl:if>
  31. </回复数>
  32. </item>
  33. </xsl:template>
  34.  
  35. <xsl:template match="//*[@id='forum' and count(./table/tbody/tr[position()>=1 and count(.//*[@class='topic']/a/text())>0])>0]" mode="列表">
  36. <item>
  37. <list>
  38. <xsl:apply-templates select="table/tbody/tr[position()>=1]" mode="list"/>
  39. </list>
  40. </item>
  41. </xsl:template>
  42. </xsl:stylesheet>""")
  43.  
  44. transform = etree.XSLT(xslt_root)
  45. result_tree = transform(doc)
  46. print(result_tree)

源代码请通过本文结尾的GitHub源下载。

2.3,抓取结果

得到的抓取结果如下图:

2.4,源代码2:翻页抓取,结果存入文件

我们对2.2的代码再做进一步修改,增加翻页抓取和存结果文件功能,代码如下:

  1. from urllib import request
  2. from lxml import etree
  3. import time
  4.  
  5. xslt_root = etree.XML("""\
  6. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  7. <xsl:template match="/">
  8. <列表>
  9. <xsl:apply-templates select="//*[@id='forum' and count(./table/tbody/tr[position()>=1 and count(.//*[@class='topic']/a/text())>0])>0]" mode="列表"/>
  10. </列表>
  11. </xsl:template>
  12.  
  13. <xsl:template match="table/tbody/tr[position()>=1]" mode="list">
  14. <item>
  15. <标题>
  16. <xsl:value-of select="*//*[@class='topic']/a/text()"/>
  17. <xsl:value-of select="*[@class='topic']/a/text()"/>
  18. <xsl:if test="@class='topic'">
  19. <xsl:value-of select="a/text()"/>
  20. </xsl:if>
  21. </标题>
  22. <回复数>
  23. <xsl:value-of select="*//*[@class='replies']/text()"/>
  24. <xsl:value-of select="*[@class='replies']/text()"/>
  25. <xsl:if test="@class='replies'">
  26. <xsl:value-of select="text()"/>
  27. </xsl:if>
  28. </回复数>
  29. </item>
  30. </xsl:template>
  31.  
  32. <xsl:template match="//*[@id='forum' and count(./table/tbody/tr[position()>=1 and count(.//*[@class='topic']/a/text())>0])>0]" mode="列表">
  33. <item>
  34. <list>
  35. <xsl:apply-templates select="table/tbody/tr[position()>=1]" mode="list"/>
  36. </list>
  37. </item>
  38. </xsl:template>
  39. </xsl:stylesheet>""")
  40.  
  41. baseurl="http://www.sina.com/cn/forum/7" #由于博客园的限制,如果你要运行该代码的话,将'sina'替换成'gooseeker‘
  42. basefilebegin="jsk_bbs_"
  43. basefileend=".xml"
  44. count=1
  45. while (count < 12):
  46. url=baseurl + "?page=" + str(count)
  47. conn=request.urlopen(url)
  48. doc = etree.HTML(conn.read())
  49. transform = etree.XSLT(xslt_root)
  50. result_tree = transform(doc)
  51. print(str(result_tree))
  52. file_obj=open(basefilebegin+str(count)+basefileend,'w',encoding='UTF-8')
  53. file_obj.write(str(result_tree))
  54. file_obj.close()
  55. count+=1
  56. time.sleep(2)

我们增加了写文件的代码,还增加了一个循环,构造每个翻页的网址,但是,如果翻页过程中网址总是不变怎么办?其实这就是动态网页内容,下面会讨论这个问题。

3,总结

这是开源Python通用爬虫项目的验证过程,在一个爬虫框架里面,其它部分都容易做成通用的,就是网页内容提取和转换成结构化的操作难于通用,我们称之为提取器。但是,借助GooSeeker可视化提取规则生成器MS谋数台 ,提取器的生成过程将变得很便捷,而且可以标准化插入,从而实现通用爬虫,在后续的文章中会专门讲解MS谋数台与Python配合的具体方法。

4,接下来阅读

本文介绍的方法通常用来抓取静态网页内容,也就是所谓的html文档中的内容,目前很多网站内容是用javascript动态生成的,一开始html是没有这些内容的,通过后加载方式添加进来,那么就需要采用动态技术,请阅读《Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTML内容

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

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

6,文档修改历史

2016-05-26:V2.0,增补文字说明;把跟帖的代码补充了进来
2016-05-29:V2.1,增加最后一章源代码下载源

Python使用xslt提取网页数据的更多相关文章

  1. python爬虫-提取网页数据的三种武器

    常用的提取网页数据的工具有三种xpath.css选择器.正则表达式 1.xpath 1.1在python中使用xpath必须要下载lxml模块: lxml官方文档 :https://lxml.de/i ...

  2. python之爬取网页数据总结(一)

    今天尝试使用python,爬取网页数据.因为python是新安装好的,所以要正常运行爬取数据的代码需要提前安装插件.分别为requests    Beautifulsoup4   lxml  三个插件 ...

  3. python笔记之提取网页中的超链接

    python笔记之提取网页中的超链接 对于提取网页中的超链接,先把网页内容读取出来,然后用beautifulsoup来解析是比较方便的.但是我发现一个问题,如果直接提取a标签的href,就会包含jav ...

  4. Python【BeautifulSoup解析和提取网页数据】

    [解析数据] 使用浏览器上网,浏览器会把服务器返回来的HTML源代码翻译为我们能看懂的样子 在爬虫中,也要使用能读懂html的工具,才能提取到想要的数据 [提取数据]是指把我们需要的数据从众多数据中挑 ...

  5. API例子:用Python驱动Firefox采集网页数据

    1,引言 本文讲解怎样用Python驱动Firefox浏览器写一个简易的网页数据采集器.开源Python即时网络爬虫项目将与Scrapy(基于twisted的异步网络框架)集成,所以本例将使用Scra ...

  6. python爬虫——爬取网页数据和解析数据

    1.网络爬虫的基本概念 网络爬虫(又称网络蜘蛛,机器人),就是模拟客户端发送网络请求,接收请求响应,一种按照一定的规则,自动地抓取互联网信息的程序.只要浏览器能够做的事情,原则上,爬虫都能够做到. 2 ...

  7. python python 入门学习之网页数据爬虫cnbeta文章保存

    需求驱动学习的动力. 因为我们单位上不了外网所以读新闻是那么的痛苦,试着自己抓取网页保存下来,然后离线阅读.今天抓取的是cnbeta科技新闻,抓取地址是http://m.cnbeta.com/wap/ ...

  8. python爬取动态网页数据,详解

    原理:动态网页,即用js代码实现动态加载数据,就是可以根据用户的行为,自动访问服务器请求数据,重点就是:请求数据,那么怎么用python获取这个数据了? 浏览器请求数据方式:浏览器向服务器的api(例 ...

  9. Python爬虫之-动态网页数据抓取

    什么是AJAX: AJAX(Asynchronouse JavaScript And XML)异步JavaScript和XML.过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新.这意 ...

随机推荐

  1. python导入matplotlib模块出错

    我的系统是linux mint.用新立得软件包安装了numpy和matplotlib.在导入matplotlib.pyplot时出错.说是没有python3-tk包. 于是就在shell中装了一下. ...

  2. Java笔记--File,FileInputStream,FileReader,InputStreamReader,BufferedReader 的使用和区别

    转自:http://hi.baidu.com/danghj/item/0ef2e2c4ab95af7489ad9e39 参考资料:  < core java > 12 章 使用 Java ...

  3. JDK PATH 和 CLASSPATH环境变量的作用及其配置

    (1)PATH环境变量的作用 在安装JDK程序之后,在安装目录下的bin目录中会提供一些开发Java程序时必备的工具程序. 对于Java的初学者,建议在命令符模式下使用这些工具程序编译运行Java程序 ...

  4. Blogger建立新文章 - Blog透视镜

    使用Blogger,建立好Blog部落格之后,接着就是建立新文章,它是Blog部落格的灵魂,先从简单开始,来了解建立新文章的标题,文章中如何上传图片,建立卷标,及设定排程日期,定时自动发布等这些功能, ...

  5. PHP CI框架下,如果配置NGINX(根目录和子目录两种模式)

    摸索了一会儿,先配置成功,再看看PATH_INFO之类的东东吧. A,根目录: location ~ \.php($|/) { root html; fastcgi_pass ; fastcgi_in ...

  6. HDU 4611Balls Rearrangement(思维)

    Balls Rearrangement Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Othe ...

  7. SQL 如何表示引号

    SELECT ename || '''' || ' 的工作是 ' || ' ' || job || '''' AS msg FROM emp WHERE deptno = 10; ' '' ' 第一个 ...

  8. c++ 友元类

    一.友元类相关概念 要将私有成员数据或函数暴露给另一个类,必须将后者声明为友元类. 注意三点: (1)友元关系不能传递 (2)友元关系不能继承 (3)友元关系不能互通

  9. onethink 验证码二维码不显示的问题

    常规思路: 1 检查GD和FreeType.在项目根目录(index.php同级)下放一个php文件 <?php echo phpinfo(); ?> 访问此文件,查看GD和FreeTyp ...

  10. MVC 简单数据传递

    Mode: namespace MVCDemo.Models { public class Data { //申明为静态 归类所有,取数据不要实例化 ; public static string st ...