Python爬虫知识体系-----解析库的使用

数据科学、数据分析、人工智能必备知识汇总-----Python爬虫-----持续更新:https://blog.csdn.net/grd_java/article/details/140574349

一、xpath

1. 安装xpath

谷歌浏览器安装xpath helper插件
  1. 下载插件
    在这里插入图片描述
  2. 将其拖入谷歌浏览器,此时高版本谷歌浏览器会报这个错误
    在这里插入图片描述
  3. 只需要将crx文件后缀改为zip,然后再次拖入即可
    在这里插入图片描述
  4. 重启浏览器后,随便打开一个页面,按下快捷键Ctrl+Shift+X或者点击右上角插件图标,就会出现解析框,证明安装成功
    在这里插入图片描述

2. python安装lxml

安装到python的scripts文件夹中

在这里插入图片描述

# 因为本人python版本较高,国内镜像暂时不支持,所以使用默认的pip镜像进行下载,会很容易失败,需要多尝试几次
pip install lxml

通过pip list命令确保自己安装成功在这里插入图片描述

编写代码测试,from lxml import etree,只要不报错就安装成功,如果报错了,看下面的解决步骤
在这里插入图片描述

pycharm使用

进入settings,选择Project:项目名,如果发现已经有lxml依然无法使用lxml的话,就需要重新配置interpreter。否则证明你安装的位置错了(可能安装在其它位置,或者其它版本的python中了),或者python版本选错了,也许是pycharm自带的python而不是我们本地的python
在这里插入图片描述

  1. 进入settings,选择Project:项目名,点击add interpreter,选择add local interpreter
    在这里插入图片描述
    在这里插入图片描述
  2. 选择existing,配置interpreter为我们使用的python的python.exe,刚刚我们就是将lxml安装到了这个python版本的scripts中,所以选择这个版本python的python.exe. 然后要点击apply后再点击ok
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  3. 此时我们从LXML中导入etree不报错就说明安装成功了
    在这里插入图片描述
'''导包(start)'''
from lxml import etree
'''导包(end)'''

3. 常用语法

为了方便讲解,我们先不爬取数据,而是用一个本地的html文件来讲解知识点,后期我们都是直接解析爬取下来的数据的,基本不会放到本地文件中然后再解析

解析方式
  1. 解析本地文件
html_tree = etree.parse('xx.html')
  1. 解析服务器响应文件
html_tree = etree.HTML(response.read().decode('utf-8'))
  1. 解析xpath,这就是我们前面安装xpath插件的原因,有了它,就可以获得xpath路径,有了路径,可以直接定位我们需要的内容
html_tree.xpath(xpath路径)
基本语法
  1. 路径查询
'''
1. //目标:查找目标所有子孙结点,不考虑层级关系
2.  /目标:查找目标直接子节点 
'''
  1. 谓词查询
'''
1. 目标[@指定属性]:查找目标中,有指定属性的,例如/li[@id]就是li标签有id属性的
2. 目标[@id="maincontent"]:查找目标中,有指定属性,属性值是maincontent的
'''
  1. 属性查询
'''
1. //@属性名:查询目标指定属性的属性值,例如/@class就是查询目标class属性的属性值
'''
  1. 模糊查询
'''
1. 目标[contains(@属性,"he")]:查询目标标签中的指定属性的属性值包含he的目标
2. 目标[starts-with(@属性,"he")]:查询目标中指定属性以he开头的目标
'''
  1. 内容查询
'''
1. 目标/text():查询目标的内容
'''
  1. 逻辑查询
'''
1. 目标[@id="head" and @class = "s_down"]: 查询目标,属性既要满足@id="head"又要满足@class = "s_down"
2. 目标1 | 目标2: 和上面不同,这个针对标签,查询目标1或目标2
'''

4. 语法基本使用

1. 创建一个html文件,添加一些简单的数据

在这里插入图片描述

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			
		</style>
	</head>
	<body>
		<ul>
			<li>北京</li>
			<li>上海</li>
			<li>广州</li>
			<li>深圳</li>
		</ul>
		<ul>
			<li>西安</li>
			<li>成都</li>
			<li>大连</li>
			<li>武汉</li>
		</ul>
	</body>
</html>
2. 一个经典的错误
  1. lxml严格遵守html规范,如果一个标签只有起始没有终止标签的话,就会提示,例如我们刚才给出的html文件中,meta标签没有终止
    在这里插入图片描述
  2. 将结束标签补上即可,再次运行就会正确的获取解析对象
    在这里插入图片描述
3. 获取body下所有子孙中的ul标签,以及所有子孙中的li标签
  1. 获取ul
    在这里插入图片描述
'''导包(start)'''
from lxml import etree
'''导包(end)'''
html_tree = etree.parse('new_file.html')
ul_list = html_tree.xpath("//body/ul")
print(ul_list)
  1. 获取li
    在这里插入图片描述
'''导包(start)'''
from lxml import etree
'''导包(end)'''
html_tree = etree.parse('new_file.html')
ul_list = html_tree.xpath("//body//li")
print(ul_list)
print(len(ul_list))
4. 找到body下所有ul标签中有id属性并且为1的,然后在这个ul标签下找所有li标签中有id的,并输出标签内容

在这里插入图片描述

其中/text()表示输出目标标签内容

'''导包(start)'''
from lxml import etree
'''导包(end)'''
html_tree = etree.parse('new_file.html')
ul_list = html_tree.xpath("//body/ul[@id='1']/li[@id]")
print(ul_list)
print(len(ul_list))
5. 查询id=1的ul下id为1.1的li,获取这个li的style属性的属性值

在这里插入图片描述

'''导包(start)'''
from lxml import etree
'''导包(end)'''

html_tree = etree.parse('new_file.html')
ul_list = html_tree.xpath("//ul/li[@id='1.1']/@style")
print(ul_list)
print(len(ul_list))
6. 模糊查询:li标签中,id属性值包含1的,和li标签中,id属性值以2开头的

在这里插入图片描述

'''导包(start)'''
from lxml import etree
'''导包(end)'''
html_tree = etree.parse('new_file.html')
ul_list = html_tree.xpath("//ul/li[contains(@id,'1')]/@id")
print("li标签中,id属性值包含1的有:",ul_list)
ul_list = html_tree.xpath("//ul/li[starts-with(@id,'2')]/@id")
print("li标签中,id属性值以2开头的有:",ul_list)

5. 爬取百度首页指定内容

在这里插入图片描述

  1. 打开百度首页,按下f12,并且打开xpath插件。我们如何知道我们写的xpath路径对不对呢
  2. 只需要在xpath插件的QUERY窗口编写代码,它会不断动态展示我们定位到了什么内容
  3. 当我们成功定位到百度一下四个字后,就可以将这段路径复制下来了
有了路径就可以写代码了

在这里插入图片描述

'''导包(start)'''
from lxml import etree
import urllib.request
import urllib.parse
'''导包(end)'''
# 1. 获取百度首页源码
url = "https://www.baidu.com/"
headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"}
request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode("utf8")

# 2. 将百度一下四个字解析出来
tree = etree.HTML(content)# 通过读取的源码,生成element tree
result = tree.xpath('//input[@id="su"]/@value')# 找到element tree中的百度一下
print(result)# 输出解析结果

6. 批量爬取图片

需求
  1. 爬取站长素材网站,高清图片中的前10页数据中的图片,直接将图片保存到本地
    在这里插入图片描述
  2. 我们发现网页源码中,图片都在class="item"的div中的img标签中。图片url在data-original属性中,图片名字在alt属性中

注意,网站采用懒加载,一定要提取正确的图片url,每个网站懒加载形式不一样,这个网站将真正url放在了data-original属性,而其它网站也要具体情况具体分析

  1. 下图我们发现,第一页url为https://sc.chinaz.com/tupian/index.html。而第二页为https://sc.chinaz.com/tupian/index_2.html,而这就是url的规律,除了第一页以外,其它页就是index_页码而已
    在这里插入图片描述
    在这里插入图片描述
xpath插件解析我们需要的信息
  1. 获取每个图片的名字alt://div[starts-with(@class,“item”)]/img/@alt
    在这里插入图片描述
  2. 获取每个图片的地址data-original://div[starts-with(@class,“item”)]/img/@data-original
    在这里插入图片描述
编写代码:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

'''导包(start)'''
from lxml import etree
import urllib.request
import urllib.parse
import os
'''导包(end)'''

headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"}
# 获取url
def get_url_byPage(page):
    if page == 1:
        url = "https://sc.chinaz.com/tupian/index.html"
    else:
        url = "https://sc.chinaz.com/tupian/index_"+str(page)+".html"
    return url
# 获取request请求对象
def get_content(url):
    request = urllib.request.Request(url=url, headers=headers)
    response = urllib.request.urlopen(request)
    content = response.read().decode("utf8")
    return content
# 获取图片文件名
def get_img_alt(content):
    tree = etree.HTML(content)# 通过读取的源码,生成element tree
    result = tree.xpath('//div[starts-with(@class,"item")]/img/@alt')# 找到element tree中的百度一下
    return result
# 获取图片路径
def get_img_url(content):
    tree = etree.HTML(content)  # 通过读取的源码,生成element tree
    result = tree.xpath('//div[starts-with(@class,"item")]/img/@data-original')  # 找到element tree中的百度一下
    return result
# 下载图片
def download_img(alt_list,img_url_list,page):
    flg = os.path.exists("./img/第" + str(page) + "页/")# 是否已经存在这个文件夹
    if flg == False: # 如果不存在就创建
        os.mkdir("./img/第" + str(page) + "页/")
    for i in range(len(alt_list)):
        urllib.request.urlretrieve(url = "https:"+img_url_list[i],filename="./img/第"+str(page)+"页/"+alt_list[i]+".jpg")

if __name__ == '__main__':
    start_page = 1
    end_page = 10
    for page in range(start_page, end_page+1):
        # 获取url
        url = get_url_byPage(page = page)
        # 获取网页源码
        content = get_content(url=url)
        # 获取图片文件名
        alt_list = get_img_alt(content=content)
        # 获取图片路径
        img_url_list = get_img_url(content=content)
        # 下载图片
        download_img(alt_list=alt_list,img_url_list=img_url_list,page=page)

二、JsonPath

1. 安装和基本使用

jsonpath主要是用于解析json数据的,例如ajax数据。与XPath是不同的,它定位的是html页面内容,而jsonPath是json数据的内容,但是我们可以对比两者的语法进行学习

依然使用pip进行安装即可,pip install jsonpath
在这里插入图片描述

JSONPath与XPath的语法对比

XPathJSONPathDescription
/$根元素
.@当前元素
/.or[]子元素
父元素
//递归下降
**通配符,表示所有元素
@属性访问字符
[][]子元素操作符
|[,]连接操作符在XPath结果合并其它结点集合。JSONPath允许name或数组索引
[start: end:step]数组分割操作从ES4借鉴
[]?()应用过滤表示式
()脚本表达式,使用在脚本引擎下
()Xpath分组
本地创建json文件当作案例

在这里插入图片描述

{ "store": {
    "book": [
      { "category": "修真",
        "author": "六道",
        "title": "坏蛋是怎样练成的",
        "price": 8.95
      },
      { "category": "修改",
        "author": "天蚕土豆",
        "title": "斗破苍穹",
        "price": 12.99
      },
      { "category": "修真",
        "author": "唐家三少",
        "title": "斗罗大陆",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      { "category": "修真",
        "author": "南派三叔",
        "title": "星辰变",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "color": "黑色",
      "price": 19.95
    }
  }
}

在这里插入图片描述

'''导包(start)'''
import json
import jsonpath
'''导包(end)'''
obj = json.load(open(file='store.json',mode='r',encoding='utf-8'))
print("书店所有书的作者(XPath:/store/book/author):",jsonpath.jsonpath(obj=obj,expr='$.store.book[*].author'))
print("所有的作者(XPath://author):",jsonpath.jsonpath(obj=obj,expr='$..author'))
print("所有元素(XPath:/store/*):",jsonpath.jsonpath(obj=obj,expr='$.store.*'))
print("所有的price(XPath:/store//price):",jsonpath.jsonpath(obj=obj,expr='$.store..price'))
print("第三本书(XPath:/store/book[3]):",jsonpath.jsonpath(obj=obj,expr='$.store.book[2]'))# jsonpath下标从0开始,xpath下标从1开始
print("最后一本书(XPath://book[last()]):",jsonpath.jsonpath(obj=obj,expr='$.store.book[(@.length-1])'))
print("前两本书(XPath://book[position()<3]):",jsonpath.jsonpath(obj=obj,expr='$..book[0,1]'))
print("前两本书(XPath://book[position()<3]):",jsonpath.jsonpath(obj=obj,expr='$..book[:2]'))
print("所有包含isbn的书(XPath://book[isbn]):",jsonpath.jsonpath(obj=obj,expr='$..book[?(@.isbn)]'))
print("价格低于10的书(XPath://book[price<3]):",jsonpath.jsonpath(obj=obj,expr='$..book[?(@.price<10)]'))
print("所有元素(XPath://*):",jsonpath.jsonpath(obj=obj,expr='$..*'))

2. 解析淘票票网站

代码实现

在这里插入图片描述

需要注意的是,淘票票网站返回的是json数据是 jsonp108(真正的json数据),所以要去掉左边的"jsonp108(“和右边的”)"

'''导包(start)'''
import json
import jsonpath
import urllib.request
import urllib.parse
'''导包(end)'''
# 请求头
headers = {
    'Host':'dianying.taobao.com',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0',
    'Accept':'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01',
    'Accept-Language':'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    # 'Accept-Encoding':'gzip, deflate, br, zstd',
    'X-Requested-With':'XMLHttpRequest',
    'bx-v':'2.5.14',
    'Connection':'keep-alive',
    'Referer':'https://dianying.taobao.com/?spm=a1z21.3046609.city.12.32c0112au7IHxT&city=513200',
    'Cookie':'thw=cn; tfstk=fkuX8Ein_tXffnEWUmdzRpGnUqzZfxTUH1NttfQV6rUYB1M-65QOklLJyWVUMlewmAZsQYqturlqFRHmERyY_m71B0hiQ-zZ61NtUrEi0Ry4CPGidm9e8elmiPq9Lp8U3t9sZP297P3bgcvQWpJezelmiP4tbJwWAr0STwAJ211mae75ygt5cjV1cxHjPSZ84jeYdJRaGotri8_TZ4NfkJhYFNQanKT2hbG2hwczoqkQTx8RlvGnrYN-pF97SYmtB5MJ-OzmYx03Vx-dyXU_hAEsqp_UGro7AqiDsThxL-iLof5B3bZTOq4q4K_LpDGxY70wEZes2c34mPXvLoctVYNbJg718J1TOG17xNF5mQO5jG07Ey4HwvEU6oFuGzOWNtaRKNQNqVR5XirYZSNHNQ6b0; isg=BEdHrg3y7XiTzGnCmulFDs3m1fsRTBsuIDClgxk0HVb9iGdKIR6Nfs5OKsjWe_Om; cna=coEXH+W0EmwCAWootOOiWFwe; t=66d61130e546591651239d33134f2cd6; cookie2=1ad21682e00857c47274c2a8240ea3cc; v=0; _tb_token_=e155e9eeba938; xlly_s=1; tb_city=513200; tb_cityName="sKKw0w=="',
    'Sec-Fetch-Dest':'empty',
    'Sec-Fetch-Mode':'cors',
    'Sec-Fetch-Site':'same-origin,'
}
# 请求地址
url = 'https://dianying.taobao.com/cityAction.json?activityId=&_ksTS=1722218140233_107&jsoncallback=jsonp108&action=cityAction&n_s=new&event_submit_doGetAllRegion=true'
request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
# 因为返回的json数据是 jsonp108(真正的json数据),所以要去掉左边的"jsonp108("和右边的")"
print("返回jsonP数据,无法直接用json解析,需要将左右圆括号切割:",content)
one_split = content.split('(')
print("将左圆括号切割:",one_split[1])
two_split = one_split[1].split(')')
print("将右圆括号切割:",two_split[0])
# 将爬取的json数据保存到本地
with open(file="淘票票.json",mode='w',encoding='utf-8') as f:
    f.write(two_split[0])
# jsonpath只支持本地文件,使用json读取本地文件
json_data = json.load(open(file='淘票票.json',mode='r',encoding='utf-8'))
print("解析出所有城市名字:",jsonpath.jsonpath(json_data,'$..regionName'))

三、BeautifulSoup

  1. 简称BS4,和lxml一样是一个html解析器,主要功能也是解析和提取html数据
  2. 缺点是没有lxml效率高,但是优点是接口设计人性化,使用起来比较方便

1. 安装和基本使用

安装

在这里插入图片描述
在这里插入图片描述

  1. 使用命令pip install bs4进行安装
  2. 代码中导入不报错,确保安装成功
依然使用本地的一个html文件进行语法讲解

在这里插入图片描述

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<style>
			
		</style>
	</head>
	<body>
		<ul id="1">
			<a href="www.baidu.com"></a>
			<li id="1.1" class="classStyle1" style="background-color: aliceblue">北京</li>
			<li id="1.2">上海</li>
			<li id="2.1">
				广州<a href="www.guangzhou.com"></a>
				<span></span>
			</li>
			<li id="2.2">深圳</li>
		</ul>
		<ul>
			<li id = "6.1" title="西安">西安</li>
			<li class="chengdu">成都</li>
			<li class="classStyle1">大连</li>
			<li id = "wuhan" title="武汉">武汉</li>
		</ul>
	</body>
</html>
获取节点的代码
  1. 要重点掌握select选择器方法,这个和css选择器的代码完全一样,写过css样式的人都知道,它可以很方便的选择目标元素应用样式
  2. 而其他的find和find_all了解即可
    在这里插入图片描述
'''导包(start)'''
from bs4 import BeautifulSoup
'''导包(end)'''
# 以utf-8格式打开html文件,指定特征为lxml,因为bs4的内核依然是lxml
soup = BeautifulSoup(open('new_file.html', encoding='utf-8'), 'lxml')
# 1. find
print("返回文档第一个li标签",soup.find(name='li'))
print("返回文档第一个title='西安'的li标签的属性",soup.find(name='li',title="西安").attrs)
print("返回文档第一个class='chengdu'的li标签",soup.find(name='li',class_="chengdu"))
# 2. find_all
print("==========================================================================================================================================")
print("返回所有的li标签",soup.find_all(name='li'))
print("返回所有的li标签和a标签中的前3个标签",soup.find_all(name=['a','li'],limit=3))
# 3. select
print("=================================================select选择器,重点需要掌握的方法==============================================================")
print("标签选择器,选择li",soup.select('li'))
print("标签选择器,选择span和a",soup.select('span,a'))
print("类选择器选择指定class,点开头就是类名。选择类名为classStyle1的",soup.select('.classStyle1'))
print("id选择器选择指定id,#开头就是id。选择id为wuhan的",soup.select('#wuhan'))
print("属性选择器选择li标签包含title属性的",soup.select('li[title]'))
print("属性选择器选择li标签包含title属性,并指定title='武汉'",soup.select('li[title="武汉"]'))
print("层级选择器选择ul标签下所有的子孙结点a",soup.select('ul a'))
print("层级选择器选择ul标签下\"直接子结点\"a",soup.select('ul>a'))
获取节点后,如何获取节点信息

在这里插入图片描述

'''导包(start)'''
from bs4 import BeautifulSoup
'''导包(end)'''
# 以utf-8格式打开html文件,指定特征为lxml,因为bs4的内核依然是lxml
soup = BeautifulSoup(open('new_file.html', encoding='utf-8'), 'lxml')
data = soup.select(selector='#wuhan')
print("通过节点对象obj.name获取标签名:",data[0].name)
print("通过节点对象obj.attrs获取节点属性字典:",data[0].attrs)
print("通过节点对象obj.attrs.get('属性名')获取节点属性字典中的id属性的属性值:",data[0].attrs.get('id'))
print("通过节点对象obj.get_text()获取标签内容:",data[0].get_text())

2. 爬取百度首页指定内容

前面使用xpath完成了爬取,而bs4和xpath是一样的,只是bs4更加方便一点,代码逻辑是完全一样的,只是将xpath的语法换成bs4而已
在这里插入图片描述

'''导包(start)'''
# from lxml import etree
import urllib.request
import urllib.parse
from bs4 import BeautifulSoup
'''导包(end)'''
# 1. 获取百度首页源码
url = "https://www.baidu.com/"
headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"}
request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode("utf8")

# 2. 将百度一下四个字解析出来
# tree = etree.HTML(content)# 通过读取的源码,生成element tree
soup = BeautifulSoup(content, 'lxml')
# result = tree.xpath('//input[@id="su"]/@value')# 找到element tree中的百度一下
data = soup.select(selector='input[id="su"]')[0]
# print(result)# 输出解析结果
print("获取到的内容:",data)
print("提取其value属性的值:",data.attrs.get('value'))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

殷丿grd_志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值