bs4 和 xpath
# 1.数据解析
解析: 根据指定的规则对数据进行提取
作用: 实现聚焦爬虫
数据解析方式:
- 正则表达式 - bs4 - xpath
1
2
3数据解析的通用原理:
数据解析需要作用在页面源码中(一组html标签组成的)
html:的核心作用是展示数据
1通用原理:
- 标签定位
- 获取文本或者属性
正则表达式实现数据解析
# 需求:爬取糗事百科中糗图数据 import requests headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } #方式1: url = 'https://pic.qiushibaike.com/system/pictures/12217/122176396/medium/OM37E794HBL3OFFF.jpg' img_data = requests.get(url=url,headers=headers).content #content返回的是byte类型的数据 with open('./123.jpg','wb') as fp: fp.write(img_data) #方式2: from urllib import request url = 'https://pic.qiushibaike.com/system/pictures/12217/122176396/medium/OM37E794HBL3OFFF.jpg' request.urlretrieve(url,'./456.jpg') - 方式2不可以使用UA伪装的机制 - urllib就是一个比较老的网络请求的模块,在requests模块没有出现之前,请求发送的操作使用的都是urllib
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2.bs4 解析模块
模块安装 :
- pip install bs4
- pip install lxml
bs4 的解析原理
- 实例化一个beautifulSoup的对象,并且将即将被解析的源码数据加载到该对象中
- 调用beautifulSoup对象中的相关属性和方法继续宁标签定位和数据提取
如何实例化BeautifulSoup对象
BeautifulSoup(fp,'lxml'):专门用作于解析本地存储的html文档中的数据
from bs4 import BeautifulSoup fp = open('./test.html','r',encoding='utf-8') soup = BeautifulSoup(fp,'lxml') #将即将被解析的页面源码加载到该对象中
1
2
3BeautifulSoup(page_text,'lxml'):专门用作于将互联网上请求到的页面源码数据进行解析
# 标签定位:
soup = BeautifulSoup(page_text,'lxml') 实例化一个对象
soup.tagName:定位到第一个TagName标签,返回的是单数
属性定位:soup.find('tagName',attrName='value'),返回也是单数
- find_all:和find用法一致,但是返回值是列表
选择器定位:select('选择器'),返回值为列表
- 标签选择器,类选择器,id选择器,层级选择器(>:一个层级,空格:多个层级)
from bs4 import BeautifulSoup fp = open('./test.html','r',encoding='utf-8') soup = BeautifulSoup(fp,'lxml') #将即将被解析的页面源码加载到该对象中 soup.p soup.find('div',class_='song') soup.find_all('div',class_='song') soup.select('.tang') soup.select('#feng') soup.select('.tang > ul > li') soup.select('.tang li') li_6 = soup.select('.tang > ul > li')[6] i_tag = li_6.i i_tag.string soup.find('div',class_='tang').text soup.find('a',id="feng")['href']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 提取数据
- 取文本:
- tag.string:标签中直系的文本内容(只提取直系内的文本)
- tag.text:标签中所有的文本内容
- 取属性:
- tag['attrName']
# 爬取三国演义整篇小说内容http://www.shicimingju.com/book/sanguoyanyi.html url = 'http://www.shicimingju.com/book/sanguoyanyi.html' page_text = requests.get(url,headers=headers).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: detail_url = 'http://www.shicimingju.com'+a['href'] chap_title = a.string #对章节详情页的url发起请求,解析详情页中的章节内容 detail_page_text = requests.get(detail_url,headers=headers).text soup = BeautifulSoup(detail_page_text,'lxml') chap_content = soup.find('div',class_="chapter_content").text fp.write(chap_title+':'+chap_content+'\n') print(chap_title,'爬取成功!') fp.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17- 取文本:
# 3.xpath 解析
模块安装 :
pip install lxml
xpath的解析原理
- 实例化一个etree类型的对象,且将页面源码数据加载到该对象中
- 需要调用该对象的xpath方法结合着不同形式的xpath表达式进行标签定位和数据提取
etree对象的实例化
- etree.parse(fileNane) 加载本地
- etree.HTML(page_text) 加载网络请求的响应
xpath方法返回的永远是一个列表
# 标签定位
在xpath表达式中最最侧的 / 表示的含义是说,当前定位的标签必须从根节点开始进行定位
xpath表达式中最左侧的 // 表示可以从任意位置进行标签定位
xpath表达式中非最左侧的 // 表示的是多个层级的意思
xpath表达式中非最左侧的 / 表示的是一个层级的意思
属性定位://tagName[@arrtName='value']
索引定位://tagName/li[3]
定位条件可以多个,使用| 分开
from lxml import etree tree = etree.parse('./test.html') tree.xpath('/html/head/meta')[0] #绝对路径 tree.xpath('//meta')[0] #相对路径,将整个页面源码中所有的meta进行定位 #属性定位 tree.xpath('//div[@class="song"]') #索引定位 tree.xpath('//div[@class="tang"]/ul/li[3]') #该索引是从1开始 #取文本 tree.xpath('//p[1]/text()') #取属性 tree.xpath('//a[@id="feng"]/@href') tree = etree.parse('./test.html') tree.xpath('/html/head/meta')[0] #绝对路径 tree.xpath('//meta')[0] #相对路径,将整个页面源码中所有的meta进行定位 #属性定位 tree.xpath('//div[@class="song"]') #索引定位 tree.xpath('//div[@class="tang"]/ul/li[3]') #该索引是从1开始 #取文本 tree.xpath('//p[1]/text()') tree.xpath('//div[@class="song"]//text()') #取属性 tree.xpath('//a[@id="feng"]/@href') # 多个条件 div.xpath('./div[1]/a[2]/h2/text() | ./div[1]/span[2]/h2/text()')[0]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 提取数据
- 取文本:
- /text():取直系的文本内容
- //text():取所有的文本内容
- 取属性直:
- tag/@attrName
# 需求:爬取boss的招聘信息 from lxml import etree headers = { # 反扒策略 'User-Agent':', 'cookie':'' } url = 'https://www.zhipin.com/job_detail/?query=python%E7%88%AC%E8%99%AB&city=101010100&industry=&position=' page_text = requests.get(url,headers=headers).text #数据解析 tree = etree.HTML(page_text) li_list = tree.xpath('//div[@class="job-list"]/ul/li') for li in li_list: # 需要将li表示的局部页面源码数据中的相关数据进行提取 # 如果xpath表达式被作用在了循环中,表达式要以./或者.//开头 detail_url = 'https://www.zhipin.com'+li.xpath('.//div[@class="info-primary"]/h3/a/@href')[0] job_title = li.xpath('.//div[@class="info-primary"]/h3/a/div/tex t()')[0] salary = li.xpath('.//div[@class="info-primary"]/h3/a/span/text()')[0] company = li.xpath('.//div[@class="info-company"]/div/h3/a/text()')[0] #对详情页的url发请求解析出岗位职责 detail_page_text = requests.get(detail_url,headers=headers).text tree = etree.HTML(detail_page_text) job_desc = tree.xpath('//div[@class="text"]//text()') job_desc = ''.join(job_desc) print(job_title,salary,company,job_desc)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25乱码处理
对获取到的内容先编码再转码:
img_name = img_name.encode('iso-8859-1').decode('gbk')
1
- 取文本:
上次更新: 2023/04/16, 18:35:33