爬虫--数据解析
数据解析基本认识
爬虫根据使用场景不同分为:通用爬虫,聚焦爬虫,增量式爬虫
聚焦爬虫:爬取页面中指定的页面内容
--编码流程
--指定URL
--发起请求
--获取响应数据
--数据解析
--持久化存储
聚焦爬虫以通用爬虫为基础,进行数据的局部提取,提取的过程即为数据解析.
数据解析分类:
--正则
--bs4
--xpath
数据解析原理概述:
--解析的局部文本内容都会在标签之间或者标签对应的属性中进行存储
--1.进行指定标签的定位
--2.标签或者标签对应的属性中存储的数据值进行提取(解析)
正则数据解析
# 图片抓取
import requests if __name__ == '__main__': url = 'https://img2020.cnblogs.com/blog/2473958/202109/2473958-20210915152350612-1868274091.png' # content返回的是二进制形式的图片数据 # .text(字符串) .content(二进制) .json()(对象) img_data = requests.get(url=url).content with open('./tupian.jpg','wb') as fp: fp.write(img_data)
# 正则解析 # <img data-v-3d1xxxa="" src="https://api.xxxx.com/image_xxx/xxx3l8zlw7.jpg" class="img-member-new"> ex = '<img data-v-3d1ecfca.*?src="(.*?)" class="img-member-new">' img_src_list = re.findall(ex,page_text,re.S)
bs4解析
bs4是python独有的解析方式.
--数据解析的原理
--1.标签定位
--2.提取标签及标签属性中存储的数据值
--bs4数据解析的原理
--1.实例化一个BeautifulSoup对象,并将页面源码数据加载到该对象中
--2.调用BeautifulSoup对象中相关属性或方法进行标签定位和数据提取
--环境安装:
--pip install bs4
--pip install lxml
--如何实例化BeautifulSoup对象
--from bs4 import BeautifulSoup
--对象实例化:
--1.将本地html文档中的数据加载到该对象中
fp = open('./网易.html','r',encoding='utf-8') soup = BeautifulSoup(fp,'lxml')
--2.将互联网上获取的页面源码加载到对象中
page_text = response.text soup = BeautifulSoup(page_text,'lxml')
--BeautifulSoup相关的对象属性和方法
--soup.tagname:返回html中第一次出现的tagname标签 --soup.find():soup.find('tagname') 返回的是文档中第一次出现的tagname标签 soup.find('tagname',class_='classname') 返回指定样式的指定标签,注意class_带下划线,因为class是python关键字 --soup.find_all(): soup.find_all('tagname') ,soup.find_all('tagname',class_='classname') 返回符合要求的所有标签列表 --soup.select(): select('某选择器(id,class,标签...选择器')'),返回的是一个列表 select(层级选择器): select('.classname>ul>li>a') 取某个样式下的ul下的li下的单一子层级所有的a标签, >大于号代表每一层都是单个层级 select('.classname>ul a ') 取某个样式下ul下的所有层级的a标签.空格表示多个层级
--获取标签之间的文本数据:
--soup.xxx.text/string/get_text()
--text/get_text():可以获取某一个标签中包含子孙标签的所有的文本内容
--string:只可以获取标签下的自身的文本内容
--获取标签中属性值:
--soup.xxx.['属性名称'] : 必须是具体到某个标签才能获取到属性值,不能是列表
案例:三国演义抓取章节名称及内容
from bs4 import BeautifulSoup import requests if __name__ == '__main__': url = 'https://www.shicimingju.com/book/sanguoyanyi.html' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome...' } page_text = requests.get(url=url, headers=headers) # 直接抓取有乱码,所以对page_text做utf-8转码 page_text.encoding='utf-8' page_text = page_text.text soup = BeautifulSoup(page_text, 'lxml') li_list = soup.select('.book-mulu > ul > li') fp = open('./sanguo.txt','w',encoding='utf-8') for li in li_list: # li标签下的a标签通过string获取其中的文本内容 title = li.a.string detail_url = 'https://www.shicimingju.com' + li.a['href'] detail_page_text = requests.get(url=detail_url, headers=headers).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,'爬取成功')
xpath解析
最常用最便捷高效的解析方式,每个编程语言都能用.
--xpath解析原理:
--1.实例化一个etree的对象,将被解析的页面源码数据加载到对象中
--2.调用etree对象中的xpath方法结合xpath表达式实现标签的定位和内容的获取
--环境的安装
--pip install lxml
--如何实例化:from lxml import etree
--1.将本地的html文档加载到etree对象
etree.parse(filePath)
--2.互联网获取的源码数据加载到对象中
etree.HTML('page_text')
--xpath('xpath表达式')
--tree.xpath('html/body/div') :/表示从根节点开始,一个/代表一个层级
--xpath('//div'):所有的div,//表示多个层级,也可以表示从任意位置开始定位
--xpath('//div[@class='c1']') :属性定位,表示类属性为c1的div标签
--xpath('//div[@class='c1']/p[3]'):索引定位,获取到类属性为c1的div标签中的第三个p标签
--获取文本:
-- /text() xpath('//div/text()') /获取的是当前标签的文本内容
-- //text() xpath('//div//text()') //获取的是当前标签及子孙标签的文本内容
--获取属性
-- /@属性名称 xpath('//img[@class="xxx"]/@src')
注意: xpath表达式中解析不了<tbody>,<html>等标签的
from lxml import etree if __name__ == '__main__': parser = etree.HTMLParser(encoding='utf-8') tree = etree.parse('xxxxns.html',parser=parser) # html下的body标签下的子标签div标签 r = tree.xpath('/html/body/div') # html标签下的所有div标签 r = tree.xpath('/html//div') # 页面所有的div标签 r = tree.xpath('//div') # 页面所有的类名为xxx的div标签 r = tree.xpath('//div[@class="xxx"]') # 页面类名为xxx的div标签下第5个li标签下的所有子标签a标签的文本内容,并取第一个a标签的内容 r = tree.xpath('//div[@class="xxx"]//li[5]/a/text()')[0] # 页面所有li标签中第七个li标签下所有文本内容 r = tree.xpath('//li[7]//text()') # 页面所有类名为xxx的div标签下的所有的子孙标签的文本内容 r = tree.xpath('//div[@class="xxx"]//text()') # xpath表达式还可以应用逻辑运算符 | 表示或者 r = tree.xpath('//img[@class="xxx"]/ul | //img[@class="xxx"]/ul/li/a') # 页面所有的类名为xxx的img标签中的src属性值列表中的第一个值 r = tree.xpath('//img[@class="xxx"]/@src')[0]
使用xpath时可能会有报错:
lxml解析数据,在使用parse加载本地的html文件的时候出现报错: lxml.etree.XMLSyntaxError: xmlParseEntityRef: no name, line 18, column 258 原因: html代码书写不规范,不符合xml解析器的使用规范 解决的办法: 使用parse方法的parser参数: parser = etree.HTMLParser(encoding=“utf-8”) selector = etree.parse(’./data/lol_1.html’,parser=parser)
乱码问题解决方法:
乱码问题解决: 1.手动对页面进行utf-8编码 response=requests.get(url=url,headers=headers) response.encoding = 'utf-8' page_text = response.text 2.通用处理中文乱码的解决方案 直接应用到乱码的内容上 img_name = img_name.encode('iso-8859-1').decode('gbk') #decode参数可以改变的
案例:58同城房源抓取
from lxml import etree import requests if __name__ == '__main__': url = 'https://bj.58.com/ershoufang/' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome...' } page_text = requests.get(url=url, headers=headers).text # print(page_text) tree = etree.HTML(page_text) div_list = tree.xpath('//div[@class="property-content"]') # li.xpath('./div/a') # 一定要加点.号,表示从li标签往内部查找,否则就会从整个页面根目录开始查找 for div in div_list: title = div.xpath('.//h3/text()')[0] price_total = div.xpath('.//p[@class="property-price-total"]//text()')[0] price_average = div.xpath('.//p[@class="property-price-average"]//text()')[0] print(title,price_total,price_average)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通