Pyhon+lxml+xpath快速实现网页爬虫(比BeautifulSoup好用)

你也可以通过我的独立博客 —— www.huliujia.com 获取本篇文章

背景

最近因为工作需要写爬虫,以前用过BeautifulSoup,所以很自然的无脑上BeautifulSoup了,不过使用过程中发现BeautifulSoup有一个致命的缺陷,就是不能支持XPath。XPath可以快速在结构化的文档(如XML,HTML)中查找、访问元素的语言,语法比正则表达式还要简单,非常容易使用。

在浏览器中其中可以方便地获取任何目标元素的XPath,简单来说XPath和文件路径很像,通过文件路径可以快速定位文件,通过XPath可以快速定位网页中的元素。这里网页和元素的关系类似文件系统和文件的关系。当然XPath提供了更多的能力。下面就是本文的重点——lxml了。lxml提供了很多功能强大的子库,本文主要用到xlml.etree(支持XPath!支持XPath!支持XPath!,重要的事说三遍)。

先看一个简单的小例子

#!env python3
from urllib.request import urlopen
from lxml import etree

sHtml = """
    
    
        
            Hello World
        
        
            

This is the first paragraph

This is the second paragraph

This is the third paragraph

"""
#解析html eleRoot = etree.HTML(sHtml) #使用xpath获取元素 listP = eleRoot.xpath("/html/body/div/p") #打印title信息 for eleP in listP: print(eleP.text)

运行结果如下:

This is the first paragraph
This is the second paragraph
This is the third paragraph

eleRoot是lxml.etree._Element类型,该类型提供了众多接口:

方法或者属性 功能
_Element.text 获取标签的文本
_Element.tag 获取标签名字(如head,div)
_Element.xpath(path) 根据XPath获取元素对象

详情参照官方文档。

xpath()返回的是一个列表,列表中包含所有符合XPath的元素。上面的例子给定的XPath是"/html/body/div/p"。

可以看到两个div的共3个p标签都符合这个路径,所以最后返回了三个p标签元素,如果想获得指定的标签,可以在给定XPath的时候添加索引,比如上图想获得second paragraph,那么path应该为"/html/body/div[2]/p[1]",没错XPath的索引是从1开始的,而不是0。这样返回的是一个只有一个_Element元素的列表。

xpath()除了可以指定绝对路径(以"/"开头的路径),还可以在元素上使用相对路径。修改上面的代码中获取和打印元素的代码为如下:

#获取body元素,然后通过相对路径访问子元素
eleBody = eleRoot.xpath("/html/body")[0]
eleP = eleBody.xpath("div[2]/p[1]")[0]
print(eleP.text)

首先获取body元素,然后通过xpath获取body元素的第二个div的第一个p,运行结果如下:

This is the second paragraph

调用etree.HTML()获得的元素为根元素,对根元素只能使用绝对路径,不能使用相对路径,其他元素均可以使用相对路径调用xpath()。

如何快速获取网页中元素的XPath

在Chrome浏览器中(其他浏览器应该也都支持这个功能),鼠标放在目标元素的上面右键 -> 点击”检查元素“,就会跳转到指定元素的标签代码上了,对选中的标签右键 -> 点击Copy -> 点击"Copy full XPath",即可获得该元素的XPath了。

XPath语法示例

注意:返回的是etree._Element的list,一个元素也会以list的格式返回

获得所有xxx元素

eleRoot.xpath("//xxx")

获得/html/body/div的所有子元素

eleRoot.xpath("html/body/div/*")

获取class为yyy的标签

eleRoot.xpath("//*[contains(@class, "yyy")]"

获取属性zzz的值为yyy的标签

eleRoot.xpath("//*[contains(@zzz, "yyy")])

如果解析中文网页出现乱码乱码的问题

请看移步另一篇文章 —— 使用lxml.etree解析中文网页时出现乱码问题的解决办法

你可能感兴趣的:(学习笔记,BeautifulSoup,xpath,爬虫,lxml,etree)