python3疯狂之路程序员首页投稿(暂停使用,暂停投稿)

简单抓站的N种方式(三)-lxml与xpath

2017-07-28  本文已影响220人  周且南_laygin

使用lxml可以解析html文档,其中需要用到xpath来选取节点,包括元素、属性、文本、命名空间、处理指令、注释和根节点。下面简单介绍一下xpath,也方便自己不时查阅,随后用一个例子具体演示使用xpath是如何抓取html文档内容的。

一、xpath简介

1、路径表达式

表达式 概述
nodename 选取此节点的所有子节点。
/ 从根节点选取 [绝对路径]
// 从匹配的当前节点选择文档中的节点 [相对路径]
. 选取当前节点。
.. 选取当前节点的父节点。
@ 选取属性。

2、表达式例子

路径表达式 表意
div 选取div元素下的的所有子节点。
/div 从根节点选取div [绝对路径]
body/div 选取属于body子元素的所有div元素
//div 选取该文档中所有div元素 [相对路径]
body//div 选取属于body后代的所有div元素
//@class 选取名为class的所有属性。

3、谓语

谓语放在方括号中用于选取特定的节点

路径表达式 结果
/body/div[1] 选取body元素下的第一个div。
/body/div[last()] 选取body元素下的最后一个div。
/body/div[last()-1] 选取body元素下的倒数第二个div。[以此类推]
//div[@class] 选取所有属性名为class的div元素。
//div[@class="age"] 选取所有属性名为class并且值为age的div元素

4、未知节点的选取

选取未知的节点,需要用到xpath的通配符,基本与正则类同

通配符 表意
* 任意元素节点
@* 任意属性节点
node() 任意类型节点

如:

路径表达式 结果
/body/* 选取body元素的所有子元素。
//* 选取文档中的所有元素。
//div[@*] 选取带有任意属性的div

5、多路径的选取

在网络爬虫中,经常会遇到这一页的内容放在一个div下,下一页就放到p标签下面了,或者标签属性不一样等等。这种情况就需要用到多路径的选取策略,相当于逻辑表达式里所说的

使用运算符| 可实现多路径的选取

路径表达式 结果
//body/div | //body/p 选取body元素的所有div和p元素。
//div | //p 选取文档中的所有div和p元素。

关于xpath的基础知识有这些基本就够了,等遇到比较复杂的网页时,也能从这些基本的表达中变通得来

二、使用lxml抓站

1、简介

大致流程

通过抓取豆瓣读书的书单列表简单演示一下,以备后查。
目标网页长成这个样子,我需要把书名和简介抓取下来,其余内容类似,比如作者、评分啊等等都可以。

目标网页-豆瓣读书

2、源码

def douban_book():
    '''拿豆瓣读书来试一试'''
    from lxml import etree
    import re

    url = r'https://book.douban.com/latest?icn=index-latestbook-all'
    header = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'}
    html = requests.get(url,headers = header).text
    lhtml = etree.HTML(html)
    #找到虚构类和非虚构类的所有图书
    all_book = lhtml.xpath('//div[@class="article" or @class="aside"]//li/div')
    
    for book in all_book:
        #找到图书标题
        book_title = re.sub(r'[\n\t\s]+','',''.join(book.xpath('h2//text()')))  #使用正则去掉换行空格等字符
        #图书简介,其余字段类似
        detail = re.sub(r'[\n\t\s]+','',''.join(book.xpath('p[@class="detail" or not(@class)]/text()')))  #因为还有一部分p标签是没有属性的,注意这里的or与not
        yield {book_title:detail}   #返回字典,也可以保存到文本或数据库

调用测试代码:

    for book in douban_book():
        print(book)

3、结果

结果
上一篇下一篇

猜你喜欢

热点阅读