整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Python如何解析HTML和XML数据

一篇我们介绍了如何解析CSV和JSON数据:如何解析互联网数据:CSV和JSON篇,今天我们将介绍如何解析HTML和XML数据。

今天的介绍能够帮助你轻而易举地从网页中(比如下面的中航电子的2017年一季度交易数据)提取自己想要的数据:

准备

在Python中可以解析html和xml数据的软件包很多,今天我们介绍的是lxml,先安装:

$ pip install lxml

如果不熟悉pip的使用,可以参考另一篇文章:如何管理python软件包。

解析HTML数据

首先,回顾一下HTML的一些基本概念:

  • 标签/tag:比如<html>, <h1>, <head>...一般成对出现,例如开始标签<html>和结束标签</html>

  • 元素/element:开始标签到结束标签整段代码,标签对之间的即为内容(content)

  • 属性/attribute:标签可拥有key=value形式的属性,比如<div class="header">...</div>

简单地理解,HTML网页就是由一组元素构成的一个集合。另外,大多数HTML标签是可以嵌套的,因此元素可以包含一系列子元素。有了这些概念做基础,我们将能够很容易理解软件包lxml的使用。实际上,在lxml里面,每个HTML元素对应一个lxml.html.HtmlElement对象,该对象提供一组标准的方法取访问包含在该元素内部的数据,比如属性、内容和子元素等。

例子

考察下面的链接,它提供中航电子在2017年第一季度的交易数据,我们打算从里面提取一些数据:

>>> url = "http://quotes.money.163.com/trade/lsjysj_600372.html?year=2017&season=1"

先把该网页爬取下来:

>>> import urllib2

>>> rsp = urllib2.urlopen(url).read()

>>> print rsp[0:15]

<!DOCTYPE html>

将字符串rsp转换成HtmlElement对象:

>>> from lxml import html

>>> doc = html.document_fromstring(rsp)

>>> type(doc)

<class 'lxml.html.HtmlElement'>

>>> doc.tag

'html'

所以其实doc就是一个html元素,它包含一些元素,比如head, body, link, div...

比如,如果你想提取该网页里面所有的链接(links):

>>> links = [ link for link in doc.iterlinks() ]

>>> len(links)

106

>>> links[0]

(<Element link at 0x1029179f0>, 'href', 'http://img1.cache.netease.com/f2e/finance/gegu/s.1064000.css', 0)

>>> links[0][2]

'http://img1.cache.netease.com/f2e/finance/gegu/s.1064000.css'

如果你想查看元素直接包含哪些子元素,可以调用getchildren()方法:

>>> doc.getchildren()

[<Element head at 0x10299a0a8>, <Element body at 0x10299a470>]

对嵌套很深的元素,如果熟悉xpath表达式,最直接的办法是调用xpath(...)方法:

>>> [ td.text for td in doc.xpath('/html/body/div[2]/div[4]/table/tr[1]/td')]

['2017-03-31', '19.02', '19.50', '19.02', '19.30', '0.36', '1.90', '102,212', '19,747', '2.53', '0.58']

此外,还可以通过find, findall, find_class, get_element_by_id等方法查找目标元素,比如:

>>> [ td.text for td in doc.findall('./body/div[2]/div[4]/table/tr[1]/td')]

['2017-03-31', '19.02', '19.50', '19.02', '19.30', '0.36', '1.90', '102,212', '19,747', '2.53', '0.58']

如果元素有属性,提取属性值也很方便,比如:

>>> form = doc.forms[0]

>>> form.tag

'form'

>>> form.attrib

{'action': '/trade/lsjysj_600372.html', 'id': 'date'}

>>> form.keys()

['id', 'action']

>>> form.get('action')

'/trade/lsjysj_600372.html'

>>> form.items()

[('id', 'date'), ('action', '/trade/lsjysj_600372.html')]

'>>> form.form_values()

[('year', '2017'), ('season', '1')]

>>> form.method

'GET'

做为一个完整的例子,下面的脚本就是爬取中航电子在2017年第一季度的数据:

输出效果:

(test) $ head -3 600372.csv

日期;开盘价;最高价;最低价;收盘价;涨跌额;涨跌幅(%);成交量(手);成交金额(万元);振幅(%);换手率(%)

2017-03-31;19.02;19.50;19.02;19.30;0.36;1.90;102,212;19,747;2.53;0.58

2017-03-31;19.02;19.50;19.02;19.30;0.36;1.90;102,212;19,747;2.53;0.58

解析xml数据

xml的格式和HTML类似,也是由标签构成的,但是要比HTML文件简单许多,看下面的xml文件片段处理:

>>> xmlstr="""\

... <target name="run" depends="jar">

... <java fork="true" classname="${main-class}">

... <classpath>

... <path refid="classpath"/>

... <path refid="application"/>

... </classpath>

... </java>

... </target>"""

>>> from lxml import etree

第一步是获取根节点:

>>> root = etree.fromstring(xmlstr)

>>> root.tag

'target'

如果要提取节点属性:

>>> root.items()

[('name', 'run'), ('depends', 'jar')]

>>> root.keys()

['name', 'depends'

>>> root.get("name")

'run'

>>> root.values()

['run', 'jar']

可以使用find, xpath等方法去获取和查找子节点:

>>> java = root.find("./java")

>>> java.tag

'java'

>>> java.keys()

['fork', 'classname']

>>> [ path.get("refid") for path in root.xpath("//path")]

['classpath', 'application']

lxml软件的功能很强大,如果有兴趣进一步了解,可以查看官方文档:

http://lxml.de/index.html

今天就写这么,欢迎大家留言、评论和关注。

Python写爬虫工具在现在是一种司空见惯的事情,每个人都希望能够写一段程序去互联网上扒一点资料下来,用于数据分析或者干点别的事情。

我们知道,爬虫的原理无非是把目标网址的内容下载下来存储到内存中,这个时候它的内容其实是一堆HTML,然后再对这些HTML内容进行解析,按照自己的想法提取出想要的数据,所以今天我们主要来讲四种在Python中解析网页HTML内容的方法,各有千秋,适合在不同的场合下使用。

首先我们随意找到一个网址,这时我脑子里闪过了豆瓣这个网站。嗯,毕竟是用Python构建的网站,那就拿它来做示范吧。

我们找到了豆瓣的Python爬虫小组主页,看起来长成下面这样。


让我们用浏览器开发者工具看看HTML代码,定位到想要的内容上,我们想要把讨论组里的帖子标题和链接都给扒出来。


通过分析,我们发现实际上我们想要的内容在整个HTML代码的 <table class="olt">这个区域里,那我们只需要想办法把这个区域内的内容拿出来就差不多了。

现在开始写代码。

1: 正则表达式大法

正则表达式通常被用来检索、替换那些符合某个模式的文本,所以我们可以利用这个原理来提取我们想要的信息。

参考以下代码。


在代码第6行和第7行,需要手动指定一下header的内容,装作自己这个请求是浏览器请求,否则豆瓣会视为我们不是正常请求会返回HTTP 418错误。

在第7行我们直接用requests这个库的get方法进行请求,获取到内容后需要进行一下编码格式转换,同样是因为豆瓣的页面渲染机制的问题,正常情况下,直接获取requests content的内容即可。

Python模拟浏览器发起请求并解析内容代码:

url = 'https://www.douban.com/group/491607/'
headers = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0"}
response = requests.get(url=url,headers=headers).content.decode('utf-8')

正则的好处是编写麻烦,理解不容易,但是匹配效率很高,不过时至今日有太多现成的HTMl内容解析库之后,我个人不太建议再手动用正则来对内容进行匹配了,费时费力。

主要解析代码:

re_div = r'<table\s+class=\"olt\">[\W|\w]+</table>'
pattern = re.compile(re_div)
content = re.findall(pattern, str(response))
re_link = r'<a .*?>(.*?)</a>'
mm = re.findall(re_link, str(content), re.S|re.M)
urls=re.findall(r"<a.*?href=.*?<\/a>",  str(content), re.I|re.S|re.M)


2: requests-html

这个库其实是我个人最喜欢的库,作则是编写requests库的网红程序员 Kenneth Reitz,他在requests的基础上加上了对html内容的解析,就变成了requests-html这个库了。


下面我们来看看范例:


我喜欢用requests-html来解析内容的原因是因为作者依据帮我高度封装过了,连请求返回内容的编码格式转换也自动做了,完全可以让我的代码逻辑简单直接,更专注于解析工作本身。

主要解析代码:

links = response.html.find('table.olt', first=True).find('a')

安装途径: pip install requests-html


3: BeautifulSoup


大名鼎鼎的 BeautifulSoup库,出来有些年头了,在Pyhton的HTML解析库里属于重量级的库,其实我评价它的重量是指比较臃肿,大而全。

还是来先看看代码。


soup = BeautifulSoup(response, 'html.parser')
links = soup.findAll("table", {"class": "olt"})[0].findAll('a')

BeautifulSoup解析内容同样需要将请求和解析分开,从代码清晰程度来讲还将就,不过在做复杂的解析时代码略显繁琐,总体来讲可以用,看个人喜好吧。

安装途径: pip install beautifulsoup4

4: lxml的XPath

lxml这个库同时 支持HTML和XML的解析,支持XPath解析方式,解析效率挺高,不过我们需要熟悉它的一些规则语法才能使用,例如下图这些规则。

来看看如何用XPath解析内容。

主要解析代码:

content = doc.xpath("//table[@class='olt']/tr/td/a")


如上图,XPath的解析语法稍显复杂,不过熟悉了语法的话也不失为一种优秀的解析手段,因为。

安装途径: pip install lxml

四种方式总结

  • 正则表达式匹配不推荐,因为已经有很多现成的库可以直接用,不需要我们去大量定义正则表达式,还没法复用,在此仅作参考了解。
  • BeautifulSoup是基于DOM的方式,简单的说就是会在解析时把整个网页内容加载到DOM树里,内存开销和耗时都比较高,处理海量内容时不建议使用。不过BeautifulSoup不需要结构清晰的网页内容,因为它可以直接find到我们想要的标签,如果对于一些HTML结构不清晰的网页,它比较适合。
  • XPath是基于SAX的机制来解析,不会像BeautifulSoup去加载整个内容到DOM里,而是基于事件驱动的方式来解析内容,更加轻巧。不过XPath要求网页结构需要清晰,而且开发难度比DOM解析的方式高一点,推荐在需要解析效率时使用。
  • requests-html 是比较新的一个库,高度封装且源码清晰,它直接整合了大量解析时繁琐复杂的操作,同时支持DOM解析和XPath解析两种方式,灵活方便,这是我目前用得较多的一个库。

  • 除了以上介绍到几种网页内容解析方式之外还有很多解析手段,在此不一一进行介绍了。

    写一个爬虫,最重要的两点就是如何抓取数据,如何解析数据,我们要活学活用,在不同的时候利用最有效的工具去完成我们的目的。

    因篇幅有限,以上四种方式的代码就不贴在文章里了,欢迎给我私信获取。

    欢迎关注我 “纸飞机编程”,获取更多有趣的python教程信息。

    ython爬虫。

    大家好,我是Python的Python爬虫。今天给大家演示一个网络爬虫的源码,就是用Python来解析html就是前端的数据。首先可以看到前面有一个支付串,支付串里包含的内容是前端的数据,它有html标签、Python标签、玻璃标签和html标签。

    然后要通过网络划重来提取标签语的数据。首先写了一个Python对象的方法。然后把这个文件,文件用PythonL解析器来解析,最后再输出这个文件。输出文件之后再打印这个文件的格式,来看一下具体效果。

    可以看到html文件已经打印成功了,它的类型是beautiful soul beautiful Python类型。然后再来获取一下当前的标签名,可以看到它或许是title标签里的内容,可以看到title标签里的内容是b。然后看打印的结果和这个一分为二。再运行一下,可以看到标签内容打印的结果是一致的。然后再获取一下当前的标签名,看一下打印的内容是否一致。再运行一下,这里出现了一个错误。是因为这里有一行代码,有一个汉字没有注视掉。

    再运行一下,可以看到这个标签名还是打印出来了,它和这里的内容是一样的。再输出一下标签,标签里面的内容。可以看到p标签点内容就可以打印出来了。然后获取一下所有的a标签,可以看到一标签的内容就打印出来了。然后读取一下所有的a标签,看一下刚才的a标签一共有一个两个三个在,第三个在这边,a标签。

    其中a标签和a标签是一样的,所以一共只打印了一个A4标签。然后查找一下,a D为Python的标签。打印一下标a d n minus 三的标签。可以看到a d 为mix三的标签,已经显示出来了。最后打印所的内容。

    把前面都做四个,可以看到标签里面的内容都出来了,看一下是不是对的。可以看到这个内容和这都对的上。最后一句,最后一句的内容就对的上。今天演示的网络花丛的视频就到这里,谢谢大家的收看。