【网络爬虫的三种解析方式】

版权声明:本文为博主原创文章,各路大佬可放心转载。 https://blog.csdn.net/qq_41964425/article/details/86071880

三种解析方式

  1. 正则解析
  2. Xpath解析
  3. BeautifulSoup解析

本文将详细为大家讲解三种聚焦爬虫中的数据解析方式。

requests模块可实现数据爬取的流程


  1. 指定url
  2. 基于requests模块发起请求
  3. 获取响应对象中的数据
  4. 进行持久化存储


       其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指定数据解析。因为,在大多数情况下,我们都是指定去使用聚焦爬虫,也就是爬取页面中指定部分的数据值,而不是整个页面的数据。因此,本文将详细为大家讲解三种聚焦爬虫中的数据解析方式。至此,我们的数据爬取流程可以修改为:

  1. 指定url
  2. 基于requests模块发起请求
  3. 获取响应中的数据
  4. 数据解析
  5. 进行持久化存储

正则解析

注:这里将从Python语言的视角讲解


re.I 忽略大小写
re.M 多行匹配
re.S 单行匹配

.* 贪婪模式
.*? 非贪婪(惰性)模式

? 0次或1次
+ 1次或多次
* 0次或1次或多次

{m} 固定m次
{m, } 至少m次
{m, n} m-n次

(\d?) 分组
(?P<name>\d?) 分组命名
(?P=name) 引用前面定义的命名分组
(?:\d?) 取消分组优先
(\d?)\1\1 通过默认分组编号向后引用(这里将匹配3个相同的数字)
(?<=pattern) 向后肯定断言的语法


关于正则的更多介绍,可见此文献:【正则表达式介绍篇】

Xpath解析

pip install lxml


示例

我们先准备好用于测试的HTML页面:

<html lang="en">
<head>
	<meta charset="UTF-8" />
	<title>Xpath解析测试</title>
</head>
<body>
	<div>
		<p>百里守约</p>
	</div>
	<div class="song">
		<p>李清照</p>
		<p>王安石</p>
		<p>苏轼</p>
		<p>柳宗元</p>
		<a href="http://www.song.com/" title="赵匡胤" target="_self">
			<span>this is span</span>
		宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a>
		<a href="" class="du">总为浮云能蔽日,长安不见使人愁</a>
		<img src="http://www.baidu.com/meinv.jpg" alt="" />
	</div>
	<div class="tang">
		<ul>
			<li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li>
			<li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li>
			<li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li>
			<li><a href="http://www.sina.com" class="du">杜甫</a></li>
			<li><a href="http://www.dudu.com" class="du">杜牧</a></li>
			<li><b>杜小月</b></li>
			<li><i>度蜜月</i></li>
			<li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li>
		</ul>
	</div>
</body>
</html>

开始测试:

from lxml import etree  # pip install lxml

# 本地文件
tree = etree.parse('test01.html')
# 如果是网络文件,应使用etree.HTML()


# 1.取出class为song的div标签下的所有文本内容
ret01 = tree.xpath('//div[@class="song"]//text()')
# //text() 表示取出某个标签下文本内容和所有子标签下的文本内容,如果存在文本,则返回的是单个元素的列表


# 2.取出class为tang的div下的直系子标签ul下的直系子标签第二个li下的直系子标签a标签下的内容
ret02 = tree.xpath('//div[@class="tang"]/ul/li[2]/a/text()')
# /text() 表示取出某个标签下的文本内容,如果存在文本,则返回的是单个或多个元素的文本
# li[2] 表示取第2个li标签

# 3.取出href属性值为空 且 class属性值为du的a标签内的文本内容
ret03 = tree.xpath('//a[@href="" and @class="du"]/text()')
# 逻辑运算:and

# 4.取出class包含 ta 的div标签下的所有文本内容(包括子孙标签)
ret04 = tree.xpath('//div[contains(@class, "ta")]//text()')
ret05 = tree.xpath('//div[starts-with(@class, "ta")]//text()')
# 模糊匹配:contains(@class, "ta") 或 starts-with(@class, "ta")

# 5.取出class为tang的div标签下的任意标签下li标签(第2个)下的a标签内href属性的值
ret06 = tree.xpath('//div[@class="tang"]//li[2]/a/@href')

# 6. / 开头的,表示最外层的标签
ret07 = tree.xpath('/html/body/div[@class="tang"]//text()')

# 定位所有class为tang的div
tree.xpath('//div[@class="tang"]')  

# 7. .// 表示从当前标签开始找
ret08 = tree.xpath('.//a/text()')

> # 8. | 表示或者
ret08 = tree.xpath('//div[@class="song"] | //div[@class="tang"]')

你还可以在浏览器中安装xpaht插件,以实现在浏览器中对xpath表达式进行验证,以及通过html元素获得xpath表达式。


实例:下载煎蛋网中的图片

import os
import base64
import requests
from lxml import etree
import urllib.request  # 使用其来快速保存内容
from fake_useragent import UserAgent  # 随机UA


url = 'http://jandan.net/pic/page-%s#comments'  # 煎蛋网

headers = {
    'User-Agent': UserAgent(use_cache_server=False).random
}

page_text = requests.get(url=url % 1, headers=headers)  # 爬取第1页的内容
page_text.encoding = 'utf-8'
content = page_text.text


# 查看页面源码:发现所有图片的src值都是一样的。
# 简单观察会发现每张图片加载都是通过jandan_load_img(this)这个js函数实现的。
# 在该函数后面还有一个class值为img-hash的标签,里面存储的是一组hash值,该值就是加密后的img地址
# 加密就是通过js函数实现的,所以分析js函数,获知加密方式,然后进行解密。
# 通过抓包工具抓取起始url的数据包,在数据包中全局搜索js函数名(jandan_load_img),然后分析该函数实现加密的方式。
# 在该js函数中发现有一个方法调用,该方法就是加密方式,对该方法进行搜索
# 搜索到的方法中会发现base64和md5等字样,md5是不可逆的所以优先考虑使用base64解密


tree = etree.HTML(content)

# 获取所有加密的图片地址
img_code_list = tree.xpath('//span[@class="img-hash"]/text()')

# 开始解密
img_url_list = []
for code_url in img_code_list:
    img_url = 'http:' + base64.b64decode(code_url).decode()
    img_url_list.append(img_url)

# 保存图片
dirname = '煎蛋图'
os.mkdir(dirname)
for url in img_url_list:
    file_name = url.split('/')[-1]
    file_path = os.path.join(dirname, file_name)
    urllib.request.urlretrieve(url=url, filename=file_path)
    print(f'{file_path}已保存')

BeautifulSoup解析


猜你喜欢

转载自blog.csdn.net/qq_41964425/article/details/86071880