python 爬虫 入门 二、数据解析(正则、bs4、xpath)

目录

一、待匹配数据获取

二、正则

三、bs4

(一)、访问属性

(二)、获取标签的值

(三)、查询方法

四、xpath

后续:登录和代理


上一节我们已经知道了如何向服务器发送请求以获得数据,今天我们就来学习如何从获得的数据中找到自己需要的东西,使用数据解析的三种工具:正则、bs4、xpath

一、待匹配数据获取

我们今天来试试国家数据网页,尝试获取下面这个框里面所有链接的url。

我们先右键网页,查看页面源代码(ps:F12元素里面的代码是网页的实时代码,和源代码有差异。)然后Ctrl+F搜索: 2020年投入产出表,可以看到有结果,前面的超链接就是我们需要的url。这表明数据是直接在网页源码中的,而不是通过脚本二次请求服务器生成的,可以直接通过页面源码找到。

接下来,使用上一节的代码来获取页面源代码。

python 复制代码
import requests

url = "https://data.stats.gov.cn/"
headers = {
    # 用户代理,某些网站验证用户代理,微微改一下,如果提示要验证码之类的,使用它
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0",
}
with requests.get(url=url, headers=headers,) as resp:
    resp.encoding = "utf-8"
    print(resp)
    with open("国家数据.html", mode="w",encoding="utf-8") as f:
        f.write(resp.text)  # 读取到网页的页面源代码"

我们下面的操作就只读取下载的html文件,而不反复请求服务器。

二、正则

使用正则表达式来匹配数据在很多python基础中都有,速度快,能适应复杂的需求,但是复杂的正则表达式不好写,难维护,容易出错。不过那些大语言模型写正则是一把好手。这里主要爬虫,关于正则表达式,给几个表看一看,用用就会了。这里贴一下python文档链接和几个表以待后续查看:正则表达式指南 --- Python 3.11.10 文档

import re # 正则

|------------|--------------------------------------------|
| findall() | 以列表形式返回所有满足数据,没有返回空列表 |
| finditer() | 返回所有匹配结果的迭代器,建议使用for+group提取 |
| search() | 返回第一个匹配结果的match对象,使用group提取,没有返回None |
| match() | 从头开始匹配,返回match对象。 相当于在正则表达式前面加了^,没有返回None |
| compile() | 预加载正则表达式 |

|-----------|-------|
| 量词 | 意义 |
| * | 0~∞次 |
| + | 1~∞次 |
| ? | 0~1次 |
| {n} | n次 |
| {n,} | n~∞次 |
| {n,m} | n~m次 |

|---------------|------------------|
| 元字符 | 意义 |
| . | 换行符以外任意字符 |
| \w | 字母数字下划线 |
| \s | 空白字符(空格 换行符 制表符) |
| \d | 数字 |
| \W | 非字母数字下划线 |
| \S | 非空白字符 |
| \D | 非数字 |
| \n | 换行符 |
| \t | 制表符 |
| ^ | 字符串开始 |
| $ | 字符串结尾 |
| a|b | 字符a或字符b |
| () | 匹配括号内的表达式 |
| [abc] | 匹配字符a或b或c |
| [^abc] | 匹配除了a、b、c的字符 |

|------|-------------------------------------|
| 规则 | 意义 |
| re.I | 忽略大小写 |
| re.L | 不建议使用,改用re.U |
| re.M | 多行匹配 |
| re.S | 令 . 可以匹配换行符 |
| re.U | 使用unicode字符集 |
| re.X | 忽略匹配表达式中的空白符和#,除非加\,令你可以在正则表达式中加注释 |

一个小细节,.*会贪婪匹配,越多越好,.*?会非贪婪匹配越少越好

好,基础知识都在上面,现在我们来尝试匹配网页吧。 通过在网页中查看,我们发现需要获取的url前后有<li><a href="和.+产出表</a><span>,所以我们可以根据这一点来写正则表达式,最终形成如下代码:

python 复制代码
import re
path = "国家数据.html"
with open(path,mode="r", encoding="utf-8") as f: # 下载源码
    data = f.read()
regular = re.compile(r'<li><a href="(?P<url>.*)">(?P<year>.*)投入产出表</a><span>')
result_1 = regular.findall(data)
result_2 = regular.finditer(data)
result_3 = regular.search(data)
result_4 = regular.match(data)
print(result_1)
for i in result_2:
    print(i.group())
    print(i.group("url"))
    print(i.group("year"))
print(result_3.group())
print(result_4)

这里面()划定了一个组,而?P<name>给组起了一个名字,结果如下:

finditer返回的迭代器是我最常用,也是我觉着最好用的。

三、bs4

bs4全称beautifulsoup4。它主要是创建解析树,用来导航、搜索、修改HTML和XML文档,效率可能比其他的略低,但比较健壮,不易出错。

from bs4 import BeautifulSoup # bs

基础用法就是先使用 bs = BeautifulSoup(data, "html.parser") 将html代码交给bs4处理为树形结构,然后在得到的bs对象中查找需要的数据。

处理后数据是一个BeautifulSoup,即文档,文档中有许多tag(标签),标签也能够包含标签,就像上图的<div>、<a>、<li>一样。我们可以通过bs.ul 来访问第一个ul标签。有的标签具有属性,像是最外层的div标签就有id属性、第一个a有href属性一样。可以像是访问字典一样,通过bs.ul.li.a["href"] 或者**bs.ul.li.a.get("href")**来访问属性的值。如果属性有多个值或者属性名字为class,会返回列表。

除了tag以外,还有NavigableString(标签的值)以及Comment(注释和特殊字符串),标签的值一般是字符串,字符串中无法包含其他标签,同时无法编辑,只能替换。可以通过**.string** 、.text获取标签的字符串。若标签内非字符串,第一种返回None,第二种会将内容转化为纯文本输出

我们要筛查的话,可以使用find() 或者**find_all()**方法来的到一个对象或者所以符合要求的对象,

find_all比find只多了一个limit参数,其他的参数相同

好,总结一下。

(一)、访问属性

标签["属性名"]

标签("属性名")

class返回列表,其他的返回字符串

(二)、获取标签的值

.string 空返回None

.text 返回内容纯文本

(三)、查询方法

find( name , attrs , recursive , string**)**

find_all( name , attrs , recursive , string, limit**)**

标签名,属性名和属性值(class_特殊),搜索全部子孙节点,字符串内容,最大返回数

除此之外,还有css选择器,但我没看,觉得不够用的可以再去学习一下。

利用上述知识,我们可以使用下面代码获得所需数据了:

python 复制代码
from bs4 import BeautifulSoup  # bs

path = "国家数据.html"
with open(path, mode="r", encoding="utf-8") as f:  # 下载源码
    data = f.read()
bs = BeautifulSoup(data, "html.parser")  # html代码交给bs处理'
ul = bs.find("ul", class_="active clearfix")  # 查找标签名为ul,属性class值为"active clearfix"的tag
data = ul.find_all("a")  # 查找所有a标签
for i in data:
    print(i["href"], i.string)

很简短,不是吗。

四、xpath

这东西比bs快点,而且有开发工具加持,能够精准定位。它和bs4挺像的,是一种专门用于XML文档定位和选择节点的语言。但用起来也挺难,这里说点简单的先用上。

from lxml import etree # 导入

xpath的节点就像是上面的tag,树形结构,跟文件夹似的,使用**etree.HTML(data)**来处理数据。

首先是xpath支持路径表达式,和我们常见的文件路径相似:

|----------|--------|
| / | 根节点开始 |
| // | 不考虑位置 |
| . | 当前节点 |
| .. | 父节点 |
| @ | 选取属性 |
| * | 通配符,任何 |
| | | 或 |
| nodename | 所有子节点 |
| text() | 获取文本 |

我们可以通过.xpath来执行路径表达式。比如还是上文中的登录部分,我们想获取登录的文本,可以使用**tree.xpath("/html/body/div[2]/div/div/ul/li[1]/a/text()")**来得到结果,什么?很长,长就对了,这就就不是给人数的。(注意,它的下标从1开始)

这就要说到上面的开发工具加持了,打开开发工具的元素页面,右键需要的元素,就能够直接复制元素的Xpath地址了。

我们再来看看这条代码:tree.xpath("//*[@id='top']/div/div/ul/li[1]/a/text()") 照样能找到位置,它用了谓语表达式,[@id='top'] 代表标签有个叫id的属性,值为'top',还能写出一些其他的谓语表达式,比如**[last()]** 表示最后一个节点,[text()="登录"] 选择文本为登录的节点,**[id>1]**选择id值大于1的节点等。

xpath还有一些接口:

|-----------|-------------|
| xpath() | 路径表达式获取节点列表 |
| find() | 查第一个匹配的节点 |
| findall() | 查所有匹配节点 |
| text | 获取文本内容 |
| attrib | 获取节点属性 |

好的,现在我们开始获取所需数据吧,要获得想要元素的位置,一点点找太麻烦了,我们可以使用左上角的检查工具,然后鼠标移动到所需的数据上,就能知道这个数据是从哪段代码中显示的了。

python 复制代码
from lxml import etree

path = "国家数据.html"
with open(path, mode="r", encoding="utf-8") as f:  # 下载源码
    data = f.read()
tree = etree.HTML(data)
ul1 = tree.xpath("/html/body/div[6]/div[3]/div[2]/div[2]/ul[1]")[0]
ul2 = tree.xpath('//ul[@class="active clearfix"]')[0]
print(ul1 == ul2)
out_data = ul1.xpath('./li/a')
print(out_data == ul1.findall("li/a"))
print(out_data == tree.xpath('//ul[@class="active clearfix"]//a'))
for i in out_data:
    print(i.attrib["href"],i.text)

方法很多,选种喜欢的用就行。

注意上面获得的url前面拼接上原网址才是完整url。

后续:登录和代理

改天写如何处理登录以及代理,详情见三、登录以及代理。

相关推荐
数据小小爬虫5 小时前
利用Java爬虫获取苏宁易购商品详情
java·开发语言·爬虫
小木_.5 小时前
【Python 图片下载器】一款专门为爬虫制作的图片下载器,多线程下载,速度快,支持续传/图片缩放/图片压缩/图片转换
爬虫·python·学习·分享·批量下载·图片下载器
lovelin+v175030409665 小时前
安全性升级:API接口在零信任架构下的安全防护策略
大数据·数据库·人工智能·爬虫·数据分析
qq_375872697 小时前
14爬虫:scrapy实现翻页爬取
爬虫·scrapy
Jelena技术达人7 小时前
Java爬虫获取1688关键字接口详细解析
java·开发语言·爬虫
小爬虫程序猿11 小时前
如何利用Python爬虫精准获取苏宁易购商品详情
开发语言·爬虫·python
API快乐传递者11 小时前
Python爬虫获取1688详情接口详细解析
开发语言·爬虫·python
小爬虫程序猿13 小时前
如何设置爬虫的访问频率?
爬虫