爬虫学习(04): 数据解析_xpath篇

一、xpath解析简介

  1. 作用:xpath是一种非常简单好用的页面提取方案。
  2. 安装:使用前,请安装好lxml模块,到本地终端下,输入以下代码,即可安装
pip install lxml
  1. 导包:
#  使用xpath的模块的时候需要导入模块
from lxml import etree

二、xpath语法

1. 用于测试的页面源代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Title</title>
</head>
<body>
    <div>
        <p>一个很厉害的人</p>
        <ol>
            <li id="10086">周大强</li>
            <li id="10010">周芷若</li>
            <li class="joy">周杰伦</li>
            <li class="jolin">蔡依林</li>
            <ol>
                <li>阿信</li>
                <li></li>
                <li>信不信</li>
            </ol>
        </ol>
    </div>
    <hr />
    <ul>
        <li><a href="http://www.baidu.com">百度</a></li>
        <li><a href="http://www.google.com">谷歌</a></li>
        <li><a href="http://www.sogou.com">搜狗</a></li>
    </ul>
    <ol>
        <li><a href="feiji">飞机</a></li>
        <li><a href="dapao">大炮</a></li>
        <li><a href="huoche">火车</a></li>
    </ol>
    <div class="job">李嘉诚</div>
    <div class="common">胡辣汤</div>
</body>
</html>

2. xpath解析入门

from lxml import etree

# 加载HTML 打开上面的html文件
f = open("xpath测试.html", mode='r', encoding='utf-8')
page_source = f.read()  # 读取文件

# 和bs4一样, 将HTML交给etree
'''
以后写代码,没有提示怎么办?
用type() 得到数据类型
去变量被赋值位置,添加 # type: 类型
'''
hm = etree.HTML(page_source)  # type:etree._Element  #  给pycharm看的 默认pycharm不知道什么类型,没有代码提示
# xpath各种用法
# 节点: 每个HTML标签叫节点
# 最外层节点: 根节点
# 内层节点: 子节点
# 父子节点: <爹><子></子></爹>

html = hm.xpath("/html")  # /根
print(html)  # 看一眼标签名(测试用, 不用记住) [<Element html at 0x10c815f00>]

body = hm.xpath("/html/body")  # 第二个/表示子节点
print(body)  # [<Element body at 0x10c859840>]

# 接下来这句话请记住, xpath提取到的内容不论多少, 都会返回列表
#  text() -> 提取标签下的内容
p = hm.xpath("/html/body/div/p/text()")  # 想要p里面的文本
print(p)  # 列表 -> ['一个很厉害的人']
print(p[0])  # 要么取0. -> 一个很厉害的人
print("".join(p))  # 要么用join()进行合并. -> 一个很厉害的人

# 如果页面结构非常复杂. 这样一层一层数下来. 过年了
# xpath我们还可以用相对定位
# // 表示在页面任意位置找,跳过前面的标签,就找符合条件的标签
p = hm.xpath("//p/text()")  
print(p)  # 依然有效 -> ['一个很厉害的人']

# 我想找到 `周大强`, `周芷若`,`周杰伦`,`周大强`,`蔡依林`
li = hm.xpath("//div/ol/li/text()")
print(li)  # -> ['周大强', '周芷若', '周杰伦', '蔡依林']

# 我想找到 `一个很厉害的人`后面ol中所有的文本
li = hm.xpath("//div/ol//text()")  # 第二个//表示所有
# 请注意. 这里多了很多空白,一般我们提取一篇文章的时候,会用这种.
# 结合字符串各种操作. 这些东西应该难不倒各位.
print(li)
print("".join(li).replace(" ", "").replace("\n", ""))  # 周大强周芷若周杰伦蔡依林阿信信信不信

3. xpath解析进阶

from lxml import etree

# 加载HTML
f = open("xpath测试.html", mode='r', encoding='utf-8')
page_source = f.read()

hm = etree.HTML(page_source)  # type:etree._Element

# 重点:根据位置数元素
# 我想要`周芷若`, 分析角度: 它是ol里第二个li
li = hm.xpath("//ol/li[2]/text()")
print(li)  # 这里莫名其妙带出了`信`, 请思考为什么? 请思考怎么干掉`信`
#  ['周芷若', '信'] 因为'//ol',而信正好也符合这个结构,所以被提取出来了

# 我想单独找`信`聊聊
li = hm.xpath("//ol/ol/li[2]/text()")
print(li)  # ['信']

# 重点:根据属性筛选元素
# 我想要id=10086的li标签中的内容0
# xpath语法中 [@属性='值']
li = hm.xpath("//li[@id='10086']/text()")
print(li)  # ['周大强']

# 我想要class是joy的内容
#  * 表示单个任意标签
li = hm.xpath("//*[@class='joy']/text()")
print(li)  # ['周杰伦']

# 我想要有class的li的内容
li = hm.xpath("//*[@class]/text()")
print(li)  # ['周杰伦', '蔡依林', '李嘉诚', '胡辣汤']

# 我想和`啊信`,`信`,`信不信`单独聊聊
li_list = hm.xpath("//ol/ol/li")
for li in li_list:
    print(li.xpath("./text()"))  # ./表示当前节点, 也就是li

# 提取`百度`, 谷歌, 搜狗的超链接href属性
# @href 表示提取属性
li_list = hm.xpath("//ul/li")
for li in li_list:
    print(li.xpath("./a/text()"))  # ./表示当前节点, 也就是li
    print(li.xpath("./a/@href"))  # @href 表示提取属性

# 我想要`火车`
li = hm.xpath("//body/ol/li[last()]/a/text()")  # last() 拿到最后一个
print(li)  # ['火车']

f.close()

4. xpath解析实战(中国票房)

'''
需求: 获取中国票房网站中的数据信息
'''
import requests
from lxml import etree
import time
import csv
#  中国票房网址
url = 'http://www.boxofficecn.com/boxoffice2022'
headers = {
    
    
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36'
}
#  首先观察数据是否在页面源代码中,再通过requests获取页面源代码
resp = requests.get(url, headers=headers)  # 获取页面源代码
main_page = etree.HTML(resp.text)  # 解析页面源代码
tr_list = main_page.xpath('//table/tbody/tr')  # 定位到tr标签下(列表)
'''
#  打开一个文件,用于写入操作
with open('2022move.text', 'w') as f:
    for tr in tr_list[1:-1]:
        # print(tr==None)
        num = tr.xpath('./td[1]//text()')[0]  # 编号
        year = tr.xpath('./td[2]//text()')  # 年份
        name = tr.xpath('./td[3]//text()')  # 电影名
        #  判断数据是否为空
        if name:
            name = ''.join(name)
        else:
            name = '未输入'
        money = tr.xpath('./td[4]//text()')  # 票房
        if not year:
            year = '未输入'
        else:
            year = ''.join(year)
        if not money:
            money = '未输入'
        else:
            money = ''.join(money)
        # print(num, year, name, money)
        f.write(f'{num}|{year}|{name}|{money}')
        f.write('\n')
'''
#  写入csv文件
with open('2022move.csv', 'w') as f:
    writer = csv.writer(f)
    for tr in tr_list[1:-1]:
        # print(tr==None)
        num = tr.xpath('./td[1]//text()')
        year = tr.xpath('./td[2]//text()')
        name = tr.xpath('./td[3]//text()')
        if num:
            num = ''.join(num)
        else:
            num = '未输入'
        if name:
            name = ''.join(name)
        else:
            name = '未输入'
        money = tr.xpath('./td[4]//text()')
        if not year:
            year = '未输入'
        else:
            year = ''.join(year)
        if not money:
            money = '未输入'
        else:
            money = ''.join(money)
        # print(num, year, name, money)
        writer.writerow([num, year, name, money])

三、关于xpath解析总结

  1. xpath提取到的内容不论多少, 都会返回列表.
  2. text() -> 提取标签下的文本内容
  3. [@属性='值'] -> 获取某指定的标签
  4. @属性 -> 表示提取某对应属性
  5. xpath解析中的索引是从1开始的,不是从0开始的
  6. // 表示在页面任意位置找,跳过前面的标签,就找符合条件的标签.

猜你喜欢

转载自blog.csdn.net/m0_48936146/article/details/127341379