爬虫——数据爬取-xpath解析器

Xpath

预备知识
HTML DOM 模型示例

HTML DOM 定义了访问和操作 HTML 文档的标准方法,以树型结构表示HTML 文档。
在这里插入图片描述

如何实现爬虫数据的解析?

1、 定位html文档中的节点
2、 提取指定节点的属性,比如href,class等
3、 获取指定节点的文本,比如a、p,div,span,div等的文本

什么是XPath?

XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性迚行遍历。
XPath可以先将 HTML文件 转换成 XML文档,然后用 XPath 查找 HTML 节点或元素。

什么是XML

可扩展标记语言(EXtensible Markup Language),W3C 的推荐标准,类似 HTML,标签需要我们自行定义,具有自我描述性,设计宗旨是传输数据,而非显示数据

XML 和 HTML 的区别

在这里插入图片描述

XPath语法
选取节点

XPath 使用路径表达式来选取 XML 文档中的节点和或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似

下面列出了最常用的路径表达式:在这里插入图片描述
一些路径表达式以及表达式的结果:
在这里插入图片描述

谓语(Predicates)

谓语用来查找某个特定的节点戒者包含某个指定的值的节点,被嵌在方括号中。

在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:在这里插入图片描述

选取未知节点

XPath 通配符可用来选取未知的 XML 元素
在这里插入图片描述
在这里插入图片描述
在下面的表格中列出了一些路径表达式,以及这些表达式的结果:
在这里插入图片描述

Xpath轴

轴可以定义相对于当前节点的节点集
在这里插入图片描述在这里插入图片描述

选取若干路径

通过在路径表达式中使用“|”运算符,可以选取若干个路径。
在这里插入图片描述

XPath的运算符

下面列出了可用在 XPath 表达式中的运算符:
在这里插入图片描述

lxml库

lxml 是一款高性能的 Python HTML/XML 的解析器,用 C 实现的,主要的功能是利用XPath语法解析和提取 HTML/XML 数据,来快速的定位特定元素以及节点信息。 lxml python 官方文档:http://lxml.de/index.html

安装

pip install lxml

解析 HTML 代码
# 使用 lxml 的 etree 库 
from lxml import etree

text = ''' 
<div>
	 <ul> 
			 <li class="item-0"><a href="link1.html">first item</a></li> 
			 <li class="item-1"><a href="link2.html">second item</a></li> 
			 <li class="item-inactive"><a href="link3.html">third item</a></li>
			 <li class="item-1"><a href="link4.html">fourth item</a></li> 
			 <li class="item-0"><a href="link5.html">fifth item</a> # 注意,此 处缺少一个 </li> 闭合标签
	 </ul>
</div> 
''' 
#利用 etree.HTML,将字符串解析为 HTML 文档 
html = etree.HTML(text)

# 按字符串序列化 HTML 文档
result = etree.tostring(html).decode() 

print(result)

lxml 可以自动修正html代码,例子里不仅补全了 li 标签,还添加了 body,html 标签。

html文件解析

hello.html 文件:

<div>     
	<ul>          
		<li class="item-0"><a href="link1.html">first item</a></li> 
		<li class="item-1"><a href="link2.html">second item</a></li>          
		<li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>          
		<li class="item-1"><a href="link4.html">fourth item</a></li>          
		<li class="item-0"><a href="link5.html">fifth item</a></li>      
	</ul>  
</div>

# lxml_parse.py

from lxml import etree

# 读取外部文件 hello.html 
html = etree.parse('./hello.html') 
result = etree.tostring(html, pretty_print=True).decode() 
print(result) 

XPath实例测试
1. 获取所有的
# xpath_li.py

from lxml import etree

html = etree.parse('hello.html')
print(type(html))  # 显示 etree.parse() 返回类型

result = html.xpath('//li')
print(result)  # 打印<li>标签的元素集合
print(len(result))
print(type(result))
print(type(result[0])) 
2. 获取
  • 标签下的所有 标签
# xpath_li.py

from lxml import etree

html = etree.parse('hello.html') 

#result = html.xpath('//li/span') 
#注意这么写是不对的: 
#因为 / 是用来获取子元素的,而 <span> 并不是 <li> 的子元素,所以,要用双斜杠 

result = html.xpath('//li//span')

print(result)
3. 获取
  • 标签下 href为 link1.html 的 标签
# xpath_li.py

from lxml import etree 

html = etree.parse('hello.html'
result = html.xpath('//li/a[@href="link1.html"]')

print(result)
4. 获取
  • 标签的所有 class属性
# xpath_li.py 

from lxml import etree

html = etree.parse('hello.html') 
result = html.xpath('//li/@class') 

print(result)

运行结果

[<Element a at 0x10ffaae18>]
5. 获取
  • 标签下的标签里的所有 class属性
# xpath_li.py

from lxml import etree 

html = etree.parse('hello.html') 
result = html.xpath('//li/a//@class') 

print(result)
7. 获取倒数第二个元素的内容
# xpath_li.py

from lxml import etree

html = etree.parse('hello.html') 
result = html.xpath('//li[last()-1]/a') 

# text 方法可以获取元素内容 
print(result[0].text)

8. 获取 class 值为 bold 的标签名
# xpath_li.py

from lxml import etree 

html = etree.parse('hello.html') 

result = html.xpath('//*[@class="bold"]') 

# tag 方法可以获取标签名 
print(result[0].tag) 
小思考

1、Python 中单引号,双引号,3个单引号及3个双引号的区别
当你用单引号’ '定义字符串的时候,它就会认为你字符串里面的双引号" "是普通字符,从而不需要转义。反之当你用双引号定义字符串的时候,就会认为你字符串里面的单引号是普通字符无需转义。3个引号实现多行输出效果戒者加注释
2、xpath中/和//的区别
/用来获取子元素,//用来获取子孙后代的元素
3、如何获取节点内容?
用text 选取文本内容
** 4、如何获取节点属性?**
用@选取属性。

接下来给大家带来我对链家二手房进行的数据爬取的代码案例:

# 案例:链家二手房
# https://sh.lianjia.com/ershoufang/
# 提取标题,链接,单价,总价,基本信息,房源特色信息
# 保存到mysql数据库


import requests
from lxml import etree

# 首先定义个基本路由
url = 'https://sh.lianjia.com/ershoufang/'

# 设置头信息
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36'
}

# 开始网页的爬取
response = requests.get(url, headers=headers)
html = response.content  # bytes字符串

# 将爬取下来的问本使用lxml里的 etree 进行转换为树桩结构
html = etree.HTML(html)

# 首先找到这个大类
list1 = html.xpath('//div[@class="info clear"]')

# 然后开始剥取所选大类内的数据
for each in list1:
    # 选取标题
    title = each.xpath('./div/a/text()')[0]
    print('title:', title)
    print("-" * 500)
    # 选取路由
    detail_url = each.xpath('./div/a/@href')[0]
    print('detail url:', detail_url)
    print("-" * 500)
    # 选取单价
    price = each.xpath('./div/div[@class="unitPrice"]/span/text()')[0]
    print(price)
    print("-" * 500)
    # 选取总价
    total = each.xpath('./div/div[@class="totalPrice"]/span/text()')[0]
    # 获取价格单位
    unit = each.xpath('./div/div[@class="totalPrice"]/text()')[0]
    print("总价:", total + unit)
    print("-" * 500)

    # 开始二次爬取 先获取到详情路由
    url = detail_url
    # 开始进去爬取
    response = requests.get(url, headers=headers)
    html = response.content
    # 爬取到了 进行html转换
    html = etree.HTML(html)

    # 然后开始找大类
    # 这个是基本属性
    list2 = html.xpath('//div[@class="box-l"]/div/div/div/div[@class="base"]/div[@class="content"]/ul/li')
    for ask in list2:
        title_1 = ask.xpath('./span/text()')[0]
        detail_1 = ask.xpath('./text()')[0]
        print(title_1, ":", detail_1)
        print("-" * 5)

    # 这个是交易属性
    list3 = html.xpath('//div[@class="box-l"]/div/div/div/div[@class="transaction"]/div[@class="content"]/ul/li')
    for ask in list2:
        title_1 = ask.xpath('./span/text()')[0]
        detail_1 = ask.xpath('./text()')[0]
        print(title_1, ":", detail_1)
        print("-" * 500)

    # 这个是房源标签
    list4 = html.xpath('//div[@class="box-l"]/div[@class="newwrap baseinform"]/div[@class="introContent showbasemore"]')
    for ask1 in list4:
        title_1 = ask1.xpath('./div[@class="tags clear"]/div[@class="name"]/text()')[0]
        detail_1 = ask1.xpath('./div[@class="tags clear"]/div/a/text()')[0].strip()
        print(title_1, ":", detail_1)
        print("-" * 500)

    # 这个是房屋特色
    list5 = html.xpath('//div[@class="box-l"]/div[@class="newwrap baseinform"]/div[@class="introContent showbasemore"]/div[@class="baseattribute clear"]')
    for ask1 in list5:
        title_1 = ask1.xpath('./div[@class="name"]/text()')
        if len(title_1) > 0:
            title_1 = title_1[0]
        else:
            title_1 = " "
        detail_1 = ask1.xpath('./div[@class="content"]/text()')
        if len(detail_1) > 0:
            detail_1 = detail_1[0].strip()
        else:
            detail_1 = " "

        print(title_1, ":", detail_1)
        print("-"*500)

纯属手打 给个赞呗!!!

JsoupXpath 是一款纯Java开发的使用xpath解析html解析器xpath语法分析与执行完全独立,html的DOM树生成借助Jsoup,故命名为JsoupXpath.为了在java里也享受xpath的强大与方便但又苦于找不到一款足够强大的xpath解析器,故开发了JsoupXpath。JsoupXpath的实现逻辑清晰,扩展方便,支持几乎全部常用的xpath语法.http://www.cnblogs.com/ 为例 "//a/@href"; "//div[@id='paging_block']/div/a[text()='Next >']/@href"; "//div[@id='paging_block']/div/a[text()*='Next']/@href"; "//h1/text()"; "//h1/allText()"; "//h1//text()"; "//div/a"; "//div[@id='post_list']/div[position()1000]/div/h3/allText()"; //轴支持 "//div[@id='post_list']/div[self::div/div/div/span[@class='article_view']/a/num()>1000]/div/h3/allText()"; "//div[@id='post_list']/div[2]/div/p/preceding-sibling::h3/allText()"; "//div[@id='post_list']/div[2]/div/p/preceding-sibling::h3/allText()|//div[@id='post_list']/div[1]/div/h3/allText()"; 在这里暂不列出框架间的对比了,但我相信,你们用了会发现JsoupXpath就是目前市面上最强大的的Xpath解析器。 快速开始 如果不方便使用maven,可以直接使用lib下的依赖包跑起来试试,如方便可直接使用如下dependency(已经上传至中央maven库,最新版本0.1.1):    cn.wanghaomiao    JsoupXpath    0.1.1 依赖配置好后,就可以使用如下例子进行体验了!String xpath="//div[@id='post_list']/div[./div/div/span[@class='article_view']/a/num()>1000]/div/h3/allText()";String doc = "..."; JXDocument jxDocument = new JXDocument(doc); List<Object> rs = jxDocument.sel(xpath); for (Object o:rs){     if (o instanceof Element){             int index = ((Element) o).siblingIndex();             System.out.println(index);     }     System.out.println(o.toString()); } 其他可以参考 cn.wanghaomiao.example包下的例子 语法 支持标准xpath语法(支持谓语嵌套),支持全部常用函数,支持全部常用轴,去掉了一些标准里面华而不实的函数和轴,下面会具体介绍。语法可以参考http://www.w3school.com.cn/xpath/index.asp 关于使用Xpath的一些注意事项 非常不建议直接粘贴Firefox或chrome里生成的Xpa
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值