🌈据说,看我文章时 关注、点赞、收藏 的 帅哥美女们 心情都会不自觉的好起来。
前言:
🧡作者简介:大家好我是 user_from_future ,意思是 “ 来自未来的用户 ” ,寓意着未来的自己一定很棒~
✨个人主页:点我直达,在这里肯定能找到你想要的~
👍专栏介绍:Python爬虫 ,一个专注于分享爬虫技巧与案例的专栏~
专栏文章直链:
【Python爬虫】自从学会了autoscraper,每天再也不用手写解析爬虫了(审核未通过,暂时无法重新发布)
【Python爬虫】你还在纠结选择哪个爬虫库嘛,全都拿来吧你
对旧博客反爬指导文章部分更新说明
beautifulsoup4无法正确解析网页的坑
QQ相关信息获取
Python爬取曾今的K歌
用“小聪明”实现连续爬取谷歌翻译
手把手带你用Python爬取反爬策略的网站
Python网页解析库
😁安装这些库
re库为标准库,不必安装,其他的在最后一行出现 Successfully installed XXX 就说明安装成功了!
pip install lxml
:
pip install pyquery
:
pip install bs4
:
pip install requests-html
(他安装的库是真的多):
🤩解析数据部分
🚗万能的正则表达式
正则表达式相信大家都接触过,没有接触过的也可以查看我曾今发过的两篇博客:从常用实例学习正则1、从常用实例学习正则2 来简单学习正则。
使用正则匹配网页中想要的数据时,有时候可能会设计比较复杂,比如:<img src="XXX" class="XX">
如果你正则写的是<img src="(.*?)" class="XX">
,那么当网页源码变成<img class="XX" src="XXX">
的时候,你就匹配不到结果了。所以正则匹配网页还是尽可能要广泛匹配,比如使用src="(.*?)"
不过这又可能匹配到其他地方。于是我们修改为<img.*src="XXX">
,这样能匹配所有img中的src属性,但这够了吗?这还不够,如果想要爬指定class的img的src属性怎么办…
所以使用正则,虽然看着写的不算多,但考虑设计正则表达式还是要花一番功夫的,而且不方便看懂,不方便后期维护。
接下来来看个实例:
首先先把本文所需的所有库和网页源码准备好,本文其他代码中就不在区分引用了:
import re
import requests
from lxml import etree
from pyquery import PyQuery
from bs4 import BeautifulSoup
from requests_html import HTMLSession
url = 'http://110.42.181.215:8866'
html = requests.get(url).text
然后呢,给自己一个需求,比如我要提取网页中id="plans"的子元素中id为plan2的ondblclick属性:
result = re.findall(r'οndblclick=\"(.*?)\"', re.findall(r'<div.*?id=\"plan2\".*?>', html)[0])[0]
# result结果:set_direction('plan2')
其他的什么网址、标题等都需要结合实际场景编写正则表达式,一般第一次提取出所有有关的标签,第二次才提取属性值,如果需要同时锁定style和class等,则需要多次匹配以确保在没有顺序的情况下能够准确获取。
🚕lxml.etree
虽然这个库并不是那么常用,但功能也挺强大的:
支持缺失自动补全
root = etree.HTML(html)
美化打印
print(etree.tostring(root, encoding=str, pretty_print=True))
# 返回:<html>......(此处省略 n 字)</html>
使用xpath获取标签,一般在浏览器开发工具里元素上右击都能找到复制XPath,这里就不教学了
plan = root.xpath('//*[@id="plans"]/div[2]')[0]
使用css选择器获取标签,一般在浏览器开发工具里元素上右击都能找到复制selector,这里就不教学了【不支持伪元素写法】
plan2 = root.cssselect('#plans>div')[1]
两种获取到的是同一个标签
print(plan == plan2)
# 返回:True
获取ondblclick属性
print(plan.get('ondblclick'))
# 返回:set_direction('plan2')
🚓pyquery.PyQuery
这个库是我用的最舒服的一个css选择器库了,没有之一,感觉上就像在用jquery。
加载源代码
q = PyQuery(html)
默认直接是支持伪元素的css选择器。有一种使用jquery选择元素的既视感,要不是python不能使用 $ 做变量名,不然写python代码就感觉在写jquery代码
tip = q('.tip')
plan = q('#plans>div:eq(1)')
直接打印返回HTML代码
print(plan)
# 返回:<div id="plan2" draggable="true" οndragstart="drag(event)" οndblclick="set_direction('plan2')"/>
相当于返回JavaScript中的 Element.innerText
print(tip.text())
# 返回:
# 游戏说明:
# 1、点击创建房间获取房间号,邀请另一半输入房间号即可加入房间。
# 2、如果电脑屏幕分辨率较低,可以按住 Ctrl 和鼠标滚轮调整缩放,推荐使用1920x1080分辨率。
# 3、如果击中敌方飞机则方块变红,否则方块变白;击中飞机核心(红色虚线)则整个飞机都会显示且变灰(代表已被击毁),比谁能更快击毁对方三架飞机吧~
# 4、每个人都要放置3架飞机,一旦放下不可更改,拖动到我方飞机区域(左)内即可,双击可以顺时针调整方向,拖动时请将飞机核心(红色虚线)对准拖动后的方块。
# 5、本游戏为回合制游戏,先摆放完者将先手,点击敌方飞机区域(右)进行攻击,击中飞机中心(红虚线边框方块)则飞机立刻坠毁,坠毁后会在图中显示飞机轮廓,不可撤销攻击,请谨慎攻击。
相当于返回JavaScript中的 Element.innerHTML
print(tip.html())
# 返回:
# <h3>游戏说明:</h3>
# <p>1、点击创建房间获取房间号,邀请另一半输入房间号即可加入房间。</p>
# <p>2、如果电脑屏幕分辨率较低,可以按住 Ctrl 和鼠标滚轮调整缩放,推荐使用<b><span style="color: red;">1920x1080</span></b>分辨率。</p>
# <p>3、如果击中敌方飞机则方块变红,否则方块变白;击中飞机核心(红色虚线)则整个飞机都会显示且变灰(代表已被击毁),比谁能更快击毁对方三架飞机吧~</p>
# <p>4、每个人都要放置3架飞机,一旦放下不可更改,拖动到我方飞机区域(左)内即可,双击可以顺时针调整方向,拖动时请将飞机核心(红色虚线)对准拖动后的方块。</p>
# <p>5、本游戏为回合制游戏,先摆放完者将先手,点击敌方飞机区域(右)进行攻击,击中飞机中心(红虚线边框方块)则飞机立刻坠毁,坠毁后会在图中显示飞机轮廓,不可撤销攻击,请谨慎攻击。</p>
可以在选择到的元素上继续选择
print(tip('p:eq(0)'))
# 返回:<p>1、点击创建房间获取房间号,邀请另一半输入房间号即可加入房间。</p>
可以直接查找到所有p标签
print(tip.find('p'))
# 返回:
# <p>1、点击创建房间获取房间号,邀请另一半输入房间号即可加入房间。</p>
# <p>2、如果电脑屏幕分辨率较低,可以按住 Ctrl 和鼠标滚轮调整缩放,推荐使用<b><span style="color: red;">1920x1080</span></b>分辨率。</p>
# <p>3、如果击中敌方飞机则方块变红,否则方块变白;击中飞机核心(红色虚线)则整个飞机都会显示且变灰(代表已被击毁),比谁能更快击毁对方三架飞机吧~</p>
# <p>4、每个人都要放置3架飞机,一旦放下不可更改,拖动到我方飞机区域(左)内即可,双击可以顺时针调整方向,拖动时请将飞机核心(红色虚线)对准拖动后的方块。</p>
# <p>5、本游戏为回合制游戏,先摆放完者将先手,点击敌方飞机区域(右)进行攻击,击中飞机中心(红虚线边框方块)则飞机立刻坠毁,坠毁后会在图中显示飞机轮廓,不可撤销攻击,请谨慎攻击。</p>
🛺bs4.BeautifulSoup
这应该是最大众的库了,相信不少人都用过。
加载解析网页。第二个位置参数是features是特征的意思,支持不同解析库:lxml、lxml-xml、html.parser、html5lib
soup = BeautifulSoup(html, 'lxml')
格式化网页字符串(缩进单位为1空格)
html = soup.prettify()
print(html)
# 返回:<html>......(此处省略 n 字)</html>
找到第一个符合的标签元素
sky = soup.find('div', attrs={'class': 'sky'})
print(sky)
# 返回:
# <div class="sky left">
# <center>我方飞机区域</center>
# <div id="left" οndragοver="allowDrop(event)" οndrοp="drop(event)"></div>
# </div>
找到所有符合的标签元素,可以使用class_来表示class类属性
sky = soup.find_all('div', class_='sky')
print(sky)
# 返回:
# [<div class="sky left">
# <center>我方飞机区域</center>
# <div id="left" οndragοver="allowDrop(event)" οndrοp="drop(event)"></div>
# </div>, <div class="sky right">
# <center>敌方飞机区域</center>
# <div id="right"></div>
# </div>]
可以从连续寻找标签元素
plans = soup.find('div', attrs={'id': 'plans'}).find_all('div')
print(plans)
# 返回:[<div draggable="true" id="plan1" οndblclick="set_direction('plan1')" οndragstart="drag(event)"></div>, <div draggable="true" id="plan2" οndblclick="set_direction('plan2')" οndragstart="drag(event)"></div>, <div draggable="true" id="plan3" οndblclick="set_direction('plan3')" οndragstart="drag(event)"></div>]
使用css选择器获取标签元素【不支持伪元素写法】
plan1 = soup.select('div#plan1')[0]
print(plan1)
# 返回:<div draggable="true" id="plan1" οndblclick="set_direction('plan1')" οndragstart="drag(event)"></div>
获取元素属性
print(plan1.get_attribute_list('ondblclick'))
# 返回:["set_direction('plan1')"]
获取元素所有属性字典
print(plan1.attrs)
# 返回:{'id': 'plan1', 'draggable': 'true', 'ondragstart': 'drag(event)', 'ondblclick': "set_direction('plan1')"}
获取提示标签中文字内容
print(soup.find('div', attrs={'class': 'tip'}).text)
# 返回:
# 游戏说明:
# 1、点击创建房间获取房间号,邀请另一半输入房间号即可加入房间。
# 2、如果电脑屏幕分辨率较低,可以按住 Ctrl 和鼠标滚轮调整缩放,推荐使用1920x1080分辨率。
# 3、如果击中敌方飞机则方块变红,否则方块变白;击中飞机核心(红色虚线)则整个飞机都会显示且变灰(代表已被击毁),比谁能更快击毁对方三架飞机吧~
# 4、每个人都要放置3架飞机,一旦放下不可更改,拖动到我方飞机区域(左)内即可,双击可以顺时针调整方向,拖动时请将飞机核心(红色虚线)对准拖动后的方块。
# 5、本游戏为回合制游戏,先摆放完者将先手,点击敌方飞机区域(右)进行攻击,击中飞机中心(红虚线边框方块)则飞机立刻坠毁,坠毁后会在图中显示飞机轮廓,不可撤销攻击,请谨慎攻击。
🚙requests_html.HTMLSession
这个库是爬取解析一体库,能自动将爬到的东西进行解析,其官网上介绍了他的优点:
- 完整的 JavaScript 支持!
- CSS 选择器(又名 jQuery 风格,感谢 PyQuery)。
- XPath 选择器,适合胆小的人。
- 模拟用户代理(就像一个真正的网络浏览器)。
- 自动跟踪重定向。
- 连接池和 cookie 持久性。
- 您熟悉和喜爱的请求体验,具有神奇的解析能力。
- 异步支持
它只支持python3.6及以上,现在应该基本不会用低版本了吧,高版本多好玩~
访问网页
session = HTMLSession()
html = session.get(url)
返回的属性
print(html)
# 返回:<Response [200]>
print(html.html)
# 返回:<HTML url='http://110.42.181.215:8866/'>
print(html.html.html)
# 返回:<html>......(此处省略 n 字)</html>
查找元素
print(html.html.find('#plan2')[0].attrs)
# 返回:{'id': 'plan2', 'draggable': 'true', 'ondragstart': 'drag(event)', 'ondblclick': "set_direction('plan2')"}
print(html.html.find('#plans>div:eq(0)')[0])
# 返回:<Element 'div' id='plan1' draggable='true' οndragstart='drag(event)' οndblclick="set_direction('plan1')">
print(html.html.xpath('/html/body/center/div[2]/center')[0].text)
# 返回:我方飞机区域
搜索文字
print(html.html.search('推荐使用{}分辨率')[0])
# 返回:<b><span style="color: red;">1920x1080</span></b>
print(html.html.search('如果击中敌方飞机则方块{red},否则方块{white};击中飞机核心(红色虚线)则整个飞机都会显示且{gray}(代表已被击毁)')['gray'])
# 返回:变灰
JavaScript支持,经过此操作之后,网页将会加载JavaScript,并将加载后的网页传回使用。
他会自动下载chromium,缺点可能是下载太慢了,要个大约10分钟
requests-html在某些方面并不一定能代替requests+BeautifulSoup这对完美组合,但正是因为这些优秀的库才让我们现在编写爬虫越来越简单
html.html.render()
智能分页——默认通过查找a标签内是否有 [‘next’, ‘more’, ‘older’] ,看上去智能,但显得有点不灵活,如果可以的话还是希望能改改
for h in session.get('https://www.python.org/jobs/').html:
print(h)
# 返回:
# <HTML url='https://www.python.org/jobs/'>
# <HTML url='https://www.python.org/jobs/?page=2'>
# <HTML url='https://www.python.org/jobs/?page=3'>
# <HTML url='https://www.python.org/jobs/?page=4'>
# <HTML url='https://www.python.org/jobs/?page=5'>
# <HTML url='https://www.python.org/jobs/?page=6'>
# <HTML url='https://www.python.org/jobs/?page=7'>
# <HTML url='https://www.python.org/jobs/?page=8'>
# <HTML url='https://www.python.org/jobs/?page=9'>
结束语
喜欢的三连关注我哦~