xpath模块
xpath模块基本使用方法
测试网页
bash
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
<ul>
<li id="l1" class="c1">北京</li>
<li id="l2">上海</li>
<li id="c3">深圳</li>
<li id="c4">武汉</li>
</ul>
</body>
</html>
bash
from lxml import etree
# 解析
# (1)本地文件 etree.parse
# (2)服务器响应的数据 response.read().decode('utf-8') ***** etree.HTML()
# xpath解析本地文件
tree = etree.parse('070_尚硅谷_爬虫_解析_xpath的基本使用.html')
print(tree.xpath('xpath路径'))
# 查找ul下面的li
print("查找ul下面的li")
li_list = tree.xpath('//body/ul/li')
print(li_list)
# 查找所有有id的属性的li标签
# text()获取标签中的内容
li_list = tree.xpath('//ul/li[@id]/text()')
print("查找所有有id的属性的li标签,text()获取标签中的内容")
print(li_list)
# 找到id为l1的li标签 注意引号的问题
li_list = tree.xpath('//ul/li[@id="l1"]/text()')
print("找到id为l1的li标签 注意引号的问题")
# 查找到id为l1的li标签的class的属性值
li = tree.xpath('//ul/li[@id="l1"]/@class')
print("查找到id为l1的li标签的class的属性值")
print(li)
# 查询id中包含l的li标签
li_list = tree.xpath('//ul/li[contains(@id,"l")]/text()')
print("查找到id为l1的li标签的class的属性值")
print(li_list)
# 查询id的值以l开头的li标签
li_list = tree.xpath('//ul/li[starts-with(@id,"c")]/text()')
print("查询id的值以l开头的li标签")
print(li_list)
#查询id为l1和class为c1的
li_list = tree.xpath('//ul/li[@id="l1" and @class="c1"]/text()')
print("查询id为l1和class为c1的")
print(li_list)
# 判断列表的长度
print(li_list)
print(len(li_list))
获取网页的源码进行解析
bash
# (1) 获取网页的源码
# (2) 解析 解析的服务器响应的文件 etree.HTML
# (3) 打印
import urllib.request
url = 'https://www.baidu.com/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}
# 请求对象的定制
request = urllib.request.Request(url = url,headers = headers)
# 模拟浏览器访问服务器
response = urllib.request.urlopen(request)
# 获取网页源码
content = response.read().decode('utf-8')
print(content)
# 解析网页源码 来获取我们想要的数据
from lxml import etree
# 解析服务器响应的文件
tree = etree.HTML(content)
# 获取想要的数据 xpath的返回值是一个列表类型的数据
result = tree.xpath('//input[@id="su"]/@value')[0]
print("输出解析结果",result)
bash
result = tree.xpath('//meta[@name="description"]/@content')[0]
print("输出解析结果",result)
bash
result = tree.xpath('//ul[@class="s-hotsearch-content" and @id="hotsearch-content-wrapper"]/li[@data-index]/a/span[@class="title-content-title"]/text()')
print("输出解析结果",result)
解析层次关系
标签跟着一层层的解析
当然如果标签的特征是独一味二的没有重复的可以直接对目标数据进行获取
bash
result = tree.xpath('//span[@class="title-content-title"]/text()')
print("输出解析结果",result)
案例:通过解析网站图片下载链接进行下载图片
第一:分析网站网址结构:
第二页
第三页
通过分析翻页对应网址的关系我们可以写出解析网址代码
bash
def create_request(page):
if(page == 1):
url = 'https://sc.chinaz.com/tupian/qinglvtupian.html'
else:
url = 'https://sc.chinaz.com/tupian/qinglvtupian_' + str(page) + '.html'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
}
request = urllib.request.Request(url = url, headers = headers)
return request
调用结果:
第二:编写解析网页的代码
找到图片的html位置
通过分析网页中的下载地址,我们发现img标签里面的data-original的数据和https://进行拼接正好可以构成图片下载地址
bash
"""
将传入的网页内容进行解析,解析出图片地址和名字返回
"""
def get_xpath(content):
tree = etree.HTML(content)
# 解析图片的地址
url_list = tree.xpath('//div[@class="tupian-list com-img-txt-list"]//div[@class="item"]/img/@data-original')
# 解析图片的名称
name_list = tree.xpath('//div[@class="tupian-list com-img-txt-list"]//div[@class="item"]/img/@alt')
return url_list, name_list
调用测试
第三:拼接下载地址,下载图片
bash
"""
传入解析好的图片地址传入进行下载
"""
def down_load(url_list, name_list):
# 循环传入的图片地址数组
for i in range(len(url_list)):
# 拿到每个图片地址
url = url_list[i]
# 拿到每个图片的名称
name = name_list[i]
# 拼接成下载地址
url = 'https:' + url
# 调用下载方法,第一个参数为下载地址,第二个参数为下载的图片名称
urllib.request.urlretrieve(url=url, filename=name + '.jpg')
整体代码
bash
# 需求 下载的前十页的图片
# https://sc.chinaz.com/tupian/qinglvtupian.html 1
# https://sc.chinaz.com/tupian/qinglvtupian_page.html
import urllib.request
from lxml import etree
"""
通过网址获取网页内容
"""
def create_request(page):
if(page == 1):
url = 'https://sc.chinaz.com/tupian/qinglvtupian.html'
else:
url = 'https://sc.chinaz.com/tupian/qinglvtupian_' + str(page) + '.html'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
}
request = urllib.request.Request(url = url, headers = headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content
"""
将传入的网页内容进行解析,解析出图片地址返回
"""
def get_xpath(content):
tree = etree.HTML(content)
# 解析图片的地址
url_list = tree.xpath('//div[@class="tupian-list com-img-txt-list"]//div[@class="item"]/img/@data-original')
# 解析图片的名称
name_list = tree.xpath('//div[@class="tupian-list com-img-txt-list"]//div[@class="item"]/img/@alt')
return url_list, name_list
"""
传入解析好的图片地址传入进行下载
"""
def down_load(url_list, name_list):
# 循环传入的图片地址数组
for i in range(len(url_list)):
# 拿到每个图片地址
url = url_list[i]
# 拿到每个图片的名称
name = name_list[i]
# 拼接成下载地址
url = 'https:' + url
# 调用下载方法,第一个参数为下载地址,第二个参数为下载的图片名称
urllib.request.urlretrieve(url=url, filename=name + '.jpg')
if __name__ == '__main__':
start_page = int(input('请输入起始页码'))
end_page = int(input('请输入结束页码'))
# 根据传入的链接地址循环调用方法
for page in range(start_page,end_page+1):
# (1) 请求对象的定制
content = create_request(page)
#print(content)
# (2)获取网页的源码
url_list, name_list = get_xpath(content)
# (3)下载
down_load(url_list, name_list)
jsonpath模块
专门用来解析json数据的模块
测试数据
bash
{ "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": {
"author": "老马",
"color": "黑色",
"price": 19.95
}
}
}
jsonpath基本使用方法
bash
import json
import jsonpath
# 加载json数据并设置编码格式
obj = json.load(open('073_尚硅谷_爬虫_解析_jsonpath.json','r',encoding='utf-8'))
# 书店所有书的作者
print("书店所有书的作者")
author_list = jsonpath.jsonpath(obj,'$.store.book[*].author')
print(author_list)
# 所有的作者
print("所有的作者")
author_list = jsonpath.jsonpath(obj,'$..author')
print(author_list)
# store下面的所有的元素
print("store下面的所有的元素")
tag_list = jsonpath.jsonpath(obj,'$.store.*')
print(tag_list)
# store里面所有东西的price
print("store里面所有东西的price")
price_list = jsonpath.jsonpath(obj,'$.store..price')
print(price_list)
# 第三个书
print("第三个书")
book = jsonpath.jsonpath(obj,'$..book[2]')
print(book)
# 最后一本书
print("最后一本书")
book = jsonpath.jsonpath(obj,'$..book[(@.length-1)]')
print(book)
# 前面的两本书
print("前面的两本书")
book_list = jsonpath.jsonpath(obj,'$..book[0,1]')
book_list = jsonpath.jsonpath(obj,'$..book[:2]')
print(book_list)
# 条件过滤需要在()的前面添加一个?
# 过滤出所有的包含isbn的书。
print("过滤出所有的包含isbn的书")
book_list = jsonpath.jsonpath(obj,'$..book[?(@.isbn)]')
print(book_list)
# 哪本书超过了10块钱
print("哪本书超过了10块钱")
book_list = jsonpath.jsonpath(obj,'$..book[?(@.price>10)]')
print(book_list)
通过jsonpath模块解析淘票票网站
bash
import urllib.request
#请求地址
url = 'https://dianying.taobao.com/cityAction.json?activityId&_ksTS=1629789477003_137&jsoncallback=jsonp138&action=cityAction&n_s=new&event_submit_doGetAllRegion=true'
#模拟浏览器的请求头
headers = {
'accept': 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01',
'accept-language': 'zh-CN,zh;q=0.9',
'cookie': 'cna=UkO6F8VULRwCAXTqq7dbS5A8; miid=949542021157939863; sgcookie=E100F01JK9XMmyoZRigjfmZKExNdRHQqPf4v9NIWIC1nnpnxyNgROLshAf0gz7lGnkKvwCnu1umyfirMSAWtubqc4g%3D%3D; tracknick=action_li; _cc_=UIHiLt3xSw%3D%3D; enc=dA18hg7jG1xapfVGPHoQCAkPQ4as1%2FEUqsG4M6AcAjHFFUM54HWpBv4AAm0MbQgqO%2BiZ5qkUeLIxljrHkOW%2BtQ%3D%3D; hng=CN%7Czh-CN%7CCNY%7C156; thw=cn; _m_h5_tk=3ca69de1b9ad7dce614840fcd015dcdb_1629776735568; _m_h5_tk_enc=ab56df54999d1d2cac2f82753ae29f82; t=874e6ce33295bf6b95cfcfaff0af0db6; xlly_s=1; cookie2=13acd8f4dafac4f7bd2177d6710d60fe; v=0; _tb_token_=e65ebbe536158; tfstk=cGhRB7mNpnxkDmUx7YpDAMNM2gTGZbWLxUZN9U4ulewe025didli6j5AFPI8MEC..; l=eBrgmF1cOsMXqSxaBO5aFurza77tzIRb8sPzaNbMiInca6OdtFt_rNCK2Ns9SdtjgtfFBetPVKlOcRCEF3apbgiMW_N-1NKDSxJ6-; isg=BBoas2yXLzHdGp3pCh7XVmpja8A8S54lyLj1RySTHq14l7vRDNufNAjpZ2MLRxa9',
'referer': 'https://dianying.taobao.com/',
'sec-ch-ua': '"Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"',
'sec-ch-ua-mobile': '?0',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
'x-requested-with': 'XMLHttpRequest',
}
#拼接请求头和请求地址
request = urllib.request.Request(url = url, headers = headers)
#进行请求
response = urllib.request.urlopen(request)
# 对返回的数据进行转码
content = response.read().decode('utf-8')
print("获取的网站数据")
print(content)
# split 切割
content = content.split('(')[1].split(')')[0]
print("切割后的数据")
print(content)
# 将获取的内容写入文件
with open('074_尚硅谷_爬虫_解析_jsonpath解析淘票票.json','w',encoding='utf-8')as fp:
fp.write(content)
import json
import jsonpath
obj = json.load(open('074_尚硅谷_爬虫_解析_jsonpath解析淘票票.json','r',encoding='utf-8'))
city_list = jsonpath.jsonpath(obj,'$..regionName')
print("jsonpath模块解析后的数据")
print(city_list)
bs4模块
测试数据
bash
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<ul>
<li id="l1">张三</li>
<li id="l2">李四</li>
<li>王五</li>
<a href="" id="" class="a1">尚硅谷</a>
<span>嘿嘿嘿</span>
</ul>
</div>
<a href="" title="a2">百度</a>
<div id="d1">
<span>
哈哈哈
</span>
</div>
<p id="p1" class="p1">呵呵呵</p>
</body>
</html>
from bs4 import BeautifulSoup
通过解析本地文件 来将bs4的基础语法进行讲解
bash
# 默认打开的文件的编码格式是gbk 所以在打开文件的时候需要指定编码
soup = BeautifulSoup(open('075_尚硅谷_爬虫_解析_bs4的基本使用.html',encoding='utf-8'),'lxml')
# 根据标签名查找节点
# 找到的是第一个符合条件的数据
print("找到的是第一个符合条件的数据")
print(soup.a)
# 获取标签的属性和属性值
print("获取标签的属性和属性值")
print(soup.a.attrs)
# bs4的一些函数
# (1)find
# 返回的是第一个符合条件的数据
print("获取标签的属性和属性值")
print(soup.find('a'))
# 根据title的值来找到对应的标签对象
print("根据title的值来找到对应的标签对象")
print(soup.find('a',title="a2"))
# 根据class的值来找到对应的标签对象 注意的是class需要添加下划线
print("根据class的值来找到对应的标签对象 注意的是class需要添加下划线")
print(soup.find('a',class_="a1"))
# (2)find_all 返回的是一个列表 并且返回了所有的a标签
print("返回的是一个列表 并且返回了所有的a标签")
print(soup.find_all('a'))
# 如果想获取的是多个标签的数据 那么需要在find_all的参数中添加的是列表的数据
print("如果想获取的是多个标签的数据 那么需要在find_all的参数中添加的是列表的数据")
print(soup.find_all(['a','span']))
# limit的作用是查找前几个数据
print("imit的作用是查找前几个数据")
print(soup.find_all('li',limit=2))
# (3)select(推荐)
# select方法返回的是一个列表 并且会返回多个数据
print("select方法返回的是一个列表 并且会返回多个数据")
print(soup.select('a'))
# 可以通过.代表class 我们把这种操作叫做类选择器
print("可以通过.代表class 我们把这种操作叫做类选择器")
print(soup.select('.a1'))
print(soup.select('#l1'))
# 属性选择器---通过属性来寻找对应的标签
# 查找到li标签中有id的标签
print("查找到li标签中有id的标签")
print(soup.select('li[id]'))
# 查找到li标签中id为l2的标签
print("查找到li标签中id为l2的标签")
print(soup.select('li[id="l2"]'))
# 层级选择器
# 后代选择器
# 找到的是div下面的li
print("找到的是div下面的li")
print(soup.select('div li'))
# 子代选择器
# 某标签的第一级子标签
# 注意:很多的计算机编程语言中 如果不加空格不会输出内容 但是在bs4中 不会报错 会显示内容
print("子代选择器")
print(soup.select('div > ul > li'))
# 找到a标签和li标签的所有的对象
print("找到a标签和li标签的所有的对象")
print(soup.select('a,li'))
# 节点信息
# 获取节点内容
obj = soup.select('#d1')[0]
# 如果标签对象中 只有内容 那么string和get_text()都可以使用
# 如果标签对象中 除了内容还有标签 那么string就获取不到数据 而get_text()是可以获取数据
# 我们一般情况下 推荐使用get_text()
print("获取节点内容")
print(obj.string)
print(obj.get_text())
# 节点的属性
obj = soup.select('#p1')[0]
# name是标签的名字
print("节点属性name是标签的名字")
print(obj.name)
# 将属性值左右一个字典返回
print("将属性值左右一个字典返回")
print(obj.attrs)
# 获取节点的属性
obj = soup.select('#p1')[0]
print(obj.attrs.get('class'))
print(obj.get('class'))
print(obj['class'])
抓取百度百科《青春有你第三季》数据
bash
import json
from bs4 import BeautifulSoup
import requests
headers = {
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"cache-control": "max-age=0"
}
def getAllUsers():
url = "https://baike.baidu.com/item/%E9%9D%92%E6%98%A5%E6%9C%89%E4%BD%A0%E7%AC%AC%E4%B8%89%E5%AD%A3?fromModule=lemma_search-box#4-3"
response = requests.get(url, headers=headers)
response.raise_for_status() # 如果请求失败,这会抛出一个异常
html_content = response.text
soup = BeautifulSoup(html_content, 'lxml')
trs = soup.find('div', attrs={'data-uuid': "go12lpqgpn"}).find_all(name='tr')
listUser = []
for tr in trs[1:]:
tds = tr.find_all('td')
name = tds[0].find('a').get_text()
head_href = tds[0].find('a').attrs['href']
head_id = head_href.split('/')[3].split('?')[0]
provice = tds[1].find('span').get_text()
height = tds[2].find('span').get_text()
weight = tds[3].find('span').get_text()
company = tds[4].find('span').get_text()
user = {'name': name, 'head_id': head_id, 'provice': provice, 'height': height, 'weight': weight,
'company': company}
listUser.append(user)
print(listUser)
return listUser
if __name__ == '__main__':
listUser = getAllUsers()
with open('user.json', 'w', encoding='utf-8') as f:
json.dump(listUser, f, ensure_ascii=False, indent=4)