数据解析
数据解析
- 聚焦爬虫:在通用爬虫的基础之上,可以将一张页面中局部指定的数据进行爬取。可以通过数据解析的方式将一张页面中局部的数据进行解析或者提取。
- 数据解析方式:
- 正则
- bs4
- xpath(重点)
- pyquery
- 聚焦爬虫编码流程:
- 指定url
- 发起请求
- 获取响应数据
- 数据解析
- 持久化存储
- 数据解析的通用原理
- html作用就是通过标签的形式进行数据的展示。在html中所有的标签遵从树状结构的。
- html所要展示的数据是可以存储在哪里?
- 存储在标签之间
- 存储在标签的属性中
- 数据解析实现的聚焦爬虫其实就是要把指定的标签中存储的数据或者属性值进行解析或者提取。
- 数据解析的通用原理
- 1.标签的定位
- 2.将该标签中存储的属性或者文本内容取出即可
正则解析
- 需求:可以将站长素材中的高清图片进行批量爬取
- 分析:
- 1.检测想要爬取的数据是否为动态加载(不是动态加载)
- 2.将当前页面的所有数据进行爬取
- 3.使用正则将每一张图片的图片地址进行解析
- 4.将图片地址发起请求,获取图片数据
- 5.将图片数据进行存储
<div class="item masonry-brick" style="position: absolute; top: 896px; left: 202px;">
<img src="//scpic.chinaz.net/files/default/imgs/2022-12-30/2367444cef2ce77f_s.jpg" style="height: 331px; display: block;" data-original="//scpic.chinaz.net/files/default/imgs/2022-12-30/2367444cef2ce77f_s.jpg" class="lazy" alt="性感欧美美女人像艺术写真图片">
<div class="bot-div">
<a class="name" href="/tupian/22123015398.htm" title="性感欧美美女人像艺术写真图片" target="_blank">性感欧美美女人像艺术写真图片</a>
</div>
</div>
# https://scpic.chinaz.net/files/default/imgs/2022-12-30/2367444cef2ce77f_s.jpg
import requests
import re
import os
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'
}
if not os.path.exists('./imgLib'):
os.mkdir('./imgLib')
url = 'https://sc.chinaz.com/tag_tupian/omeimeinu.html'
page_text = requests.get(url=url,headers=headers)
page_text.encoding = 'utf-8'
page_text = page_text.text
#使用正则将图片地址进行提取
re_ex = 'data-original="(.*?)".*? class='
#正则解析数据时,遇到换行会停止匹配数据。re.S就可以让正则遇到换行不停止匹配
#在爬虫中必须使用re.S
img_src = re.findall(re_ex,page_text,re.S)
# print(img_src)
for src in img_src:
img_url = 'https:'+src
img_name = src.split('/')[-1]
img_path = './imgLib/'+img_name
img_content = requests.get(url=img_url).content
with open(img_path,'wb') as fp:
fp.write(img_content)
print(img_name,'下载成功!')
#将每一个页码对应的图片数据进行下载
if not os.path.exists('./imgLib'):
os.mkdir('./imgLib')
#定义一个通用的url模板
url_model = 'https://sc.chinaz.com/tupian/rentiyishu_%d.html'
page_num = 1
for page in range(1,10):
print('正在下载第%d页的数据......'%page)
if page == 1:
url = 'https://sc.chinaz.com/tupian/rentiyishu.html'
else:
url = format(url_model%page)
page_text = requests.get(url=url,headers=headers)
page_text.encoding = 'utf-8'
page_text = page_text.text
#使用正则将图片地址进行提取
re_ex = 'data-original="(.*?)".*? class='
#正则解析数据时,遇到换行会停止匹配数据。re.S就可以让正则遇到换行不停止匹配
#在爬虫中必须使用re.S
img_src = re.findall(re_ex,page_text,re.S)
# print(img_src)
for src in img_src:
img_url = 'https:'+src
img_name = src.split('/')[-1]
img_path = './imgLib/'+img_name
img_content = requests.get(url=img_url).content
with open(img_path,'wb') as fp:
fp.write(img_content)
print(img_name,'下载成功!')
print('所有图片下载完成')
- 浏览器开发工具中Elements和Network选项卡中对应的页面源码内容的区别:
- 如果当前页面中存在动态加载数据的话:
- Elements:对应的源码中是存有动态加载数据
- 将所有请求的内容加载完毕后整合完整的页面数据
- Network:对应的源码中是没有存在动态加载数据
- Elements:对应的源码中是存有动态加载数据
- 如果当前页面中存在动态加载数据的话:
bs4解析
-
环境安装
- pip install bs4
- pip install lxml
-
bs4数据解析的原理
- 1.实例化一个BeautifulSoup对象,需要将被解析的页面源码内容加载到该对象中
- 2.调用BeautifulSoup对象中的相关属性&方法进行标签定位和数据提取
-
BeautifulSoup对象的实例化:
- BeautifulSoup(fp,'lxml'):可以将本地存储的一张html页面加载到该对象中进行数据解析
- BeautifulSoup(page_text,'lxml'):可以将从互联网上请求到的页面源码数据进行数据解析
-
标签定位
- soup.tagName:定位到第一次出现的该标签
- 属性定位:可以根据一个具体的属性定位到该属性对应的标签
- find('tagName',attrName='attrValue')返回的是单数
- find_all('tagName',attrName='attrValue')返回的是复数
- 选择器定位:类选择器,id选择器,层级选择器
- select('.song')类选择器
- select('#feng')id选择器
- 层级选择器
- 大于号表示一个层级
- 空格表示多个层级
-
取文本
- tagName.string:只可以取得标签中直系的文本内容
- tagName.text:可以取得标签中所有的文本内容
-
取属性
from bs4 import BeautifulSoup
fp = open('./test.html','r',encoding='utf-8')
soup = BeautifulSoup(fp,'lxml')
# print(soup) #返回的是加载到该对象中的页面源码数据
soup.title
soup.div
soup.find('div',class_='song')
soup.find_all('div',class_='song')
soup.select('.song')
soup.select('#feng')
soup.select('.tang > ul > li > a')
soup.select('.tang a')
soup.title.string
soup.title.text
soup.find('div',class_='song').text
soup.find('a',id='feng')['href']
- 需求:使用bs4实现将诗词名句网站中三国演义小说的每一章的内容爬去到本地磁盘进行存储 - http://www.shicimingju.com/book/sanguoyanyi.html
- 思路:
- 1.将首页的页面源码内容进行爬取
- 2.数据解析
- 章节标题
- 详情页的url
- 3.对详情页的url发起请求获取详情页的页面源码内容
- 4.对详情页中的章节内容进行数据解析
- 5.将标题和内容进行持久化存储
https://www.shicimingju.com/book/sanguoyanyi/1.html
from bs4 import BeautifulSoup
url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
page_text = requests.get(url=url,headers=headers)
page_text.encoding = 'utf-8'
page_text = page_text.text
#数据解析
soup = BeautifulSoup(page_text,'lxml')
a_list = soup.select('.book-mulu > ul > li > a')
fp = open('./sanguo.txt','w',encoding='utf-8')
for a in a_list:
title = a.string
detail_url = 'http://www.shicimingju.com'+a['href']
detail_page_text = requests.get(url=detail_url,headers=headers)
detail_page_text.encoding = 'utf-8'
detail_page_text = detail_page_text.text
detail_soup = BeautifulSoup(detail_page_text,'lxml')
div_tag = detail_soup.find('div',class_='chapter_content')
content = div_tag.text
fp.write(title+':'+content+'\n')
print(title,'已经下载成功!!!')
fp.close()
- bs4标签定位的特性
- 可以直接将定位到的标签以字符串的形式进行输出
xpath解析
- 环境的安装:pip install lxml
- 实现流程:
- 1.实例化一个etree类型的对象,且把即将被解析的页面源码内容加载到该对象中
- 2.调用etree对象中的xpath方法结合着不同形式的xpath表达式进行标签定位和数据提取
- etree对象的实例化
- etree.parse(fileName):将本地存储的html文档进行数据解析
- etree.HTML(page_text):将请求到的页面源码数据进行解析
- xpath表达式
- 最左侧的/:xpath表达式需要从html树状结构的最外层的标签逐步的进行其他标签的定位
- 非最最侧的/:表示一个层级的意思
- 最左侧的//:可以从任意位置定位标签(推荐)
- 非最左侧的//:表示多个层级
- 标签定位
- 属性定位://tagName[@attrName="attrValue"]
- 索引定位://tagName[index]:index是从1开始
- 模糊匹配:
- //div[contains(@class, "ng")]
- //div[starts-with(@class, "ta")]
- 取文本
- /text():取得直系的文本内容(返回列表元素是单个)
- //text():取得所有的文本内容(返回列表元素是多个)
- 取属性
- /@attrName
from lxml import etree
import requests
import re
import os
from urllib import request
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'
}
tree = etree.parse('./test.html')
tree.xpath('/html/head/title')
tree.xpath('/html//title')
tree.xpath('//title')
tree.xpath('//div[@class="tang"]//text()')
tree.xpath('//a[@id="feng"]/@href')
- 将糗事百科中的段子标题和内容进行解析爬取
url_model = 'https://www.qiushibaike.com/text/page/%d/'
for page in range(1,4):
url = format(url_model%page)
page_text = requests.get(url=url,headers=headers).text
tree = etree.HTML(page_text)
#列表中每一个div标签都包含了我们要解析的内容
#xpath是在做全局数据解析
div_list = tree.xpath('//div[@class="col1 old-style-col1"]/div')
for div in div_list:
#div表示:div是一个Element类型的对象,表示就是页面中的一个指定的div标签
#div:html源码中的一个局部数据
#局部数据解析中:./表示xpath方法调用者表示的标签
author = div.xpath('./div[1]/a[2]/h2/text()')[0] #局部数据解析,只可以定位div这个局部数据中的相关标签
content = div.xpath('./a[1]/div/span//text()')
content = ''.join(content)
print(author,content)
-
语音合成技术实现
- 基于百度AI实现的语音合成
-
xpath图片数据爬取
import time
import os
from urllib import request
if not os.path.exists('./imgLibs'):
os.mkdir('./imgLibs')
imgLibs = './imgLibs/'
url_model = 'https://pic.netbian.com/4kmeinv/index_%d.html'
for page in range(1,6):
print('正在下载第%d页的图片......'%page)
if page == 1:
url = 'http://pic.netbian.com/4kmeinv/'
else:
url = format(url_model%page)
page_text = requests.get(url,headers=headers)
page_text.encoding = 'gbk'
page_text = page_text.text
tree = etree.HTML(page_text)
li_list = tree.xpath('//*[@id="main"]/div[3]/ul/li')
for li in li_list:
img_name = li.xpath('./a/img/@alt')[0]+'.jpg'
img_src = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0]
img_path = imgLibs+img_name
request.urlretrieve(img_src,img_path)
# img_text = requests.get(url=img_src,headers=headers).content
# with open(img_name,'wb') as fp:
# fp.write(img_text)
print(img_name,'图片下载成功')
-
试题:
- url:https://m.vmall.com/help/hnrstoreaddr.htm
- 爬取每一个店铺详情页中的店铺地址+营业时间
-
step1:尝试将某一个店铺详情页的指定数据获取
url = 'https://openapi.vmall.com/mcp/offlineshop/getShopById'
params = {
'portal': '2',
'version': '10',
'country': 'CN',
'shopId': '111616',
'lang': 'zh-CN',
}
json_data = requests.get(url=url,headers=headers,params=params).json()
address = json_data['shopInfo']['address']
time_ = json_data['shopInfo']['serviceTime']
print(address,time_)
- step2:获取每一家店铺的id即可
main_url = 'https://openapi.vmall.com/mcp/offlineshop/getShopList'
data = {"portal":2,"lang":"zh-CN","country":"CN","brand":1,"province":"河北","city":"邯郸","pageNo":1,"pageSize":40}
main_json_data = requests.post(url=main_url,headers=headers,json=data).json()
for dic in main_json_data['shopInfos']:
id_ = dic['id']
url = 'https://openapi.vmall.com/mcp/offlineshop/getShopById'
params = {
'portal': '2',
'version': '10',
'country': 'CN',
'shopId': id_,
'lang': 'zh-CN',
}
json_data = requests.get(url=url,headers=headers,params=params).json()
address = json_data['shopInfo']['address']
time_ = json_data['shopInfo']['serviceTime']
print(address,time_)
#爬取城市名称
url = 'https://www.aqistudy.cn/historydata/'
page_text = requests.get(url=url,headers=headers).text
tree = etree.HTML(page_text)
hot_cities = tree.xpath('//div[@class="bottom"]/ul/li/a/text()')
all_cities = tree.xpath('//div[@class="bottom"]/ul/div[2]/li/a/text()')
#爬取城市名称
url = 'https://www.aqistudy.cn/historydata/'
page_text = requests.get(url=url,headers=headers).text
tree = etree.HTML(page_text)
all_cities = tree.xpath('//div[@class="bottom"]/ul/div[2]/li/a/text() | //div[@class="bottom"]/ul/li/a/text()')
all_cities
-
xpath表达式中的管道符有什么好处
- 可以大大的增加xpath表达式的通用性
-
如果想要解析出携带html标签的页面局部内容,如何实现?
- bs4
-
爬取站长素材中免费的简历模板
url = 'https://sc.chinaz.com/jianli/free.html'
download_url = 'https://downsc.chinaz.net/Files/DownLoad/jianli/202301/zjianli1020.rar'
src="//scpic2.chinaz.net/Files/pic/jianli/202301/zjianli1020_s.jpg"
from lxml import etree
import requests
import os
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'
}
if not os.path.exists('./download_model'):
os.mkdir('./download_model')
download_path = './download_model/'
page_text = requests.get(url=url,headers=headers)
page_text.encoding = 'utf-8'
page_text = page_text.text
tree = etree.HTML(page_text)
tree_list = tree.xpath('//div[@id="container"]/div/a[1]')
for img in tree_list:
img_name = download_path+img.xpath('./img/@alt')[0]
img_src = img.xpath('./img/@src')[0]
download_url = 'https://downsc.chinaz.net/Files/DownLoad'+img_src.split('pic')[-1].replace('_s.jpg','.rar')
download_file = requests.get(url=download_url,headers=headers).content
with open(img_name+'.rar','wb') as fp:
fp.write(download_file)
print(img_name,'下载成功')