一、基础知识
1、常见的数据解析方式:
-
正则:既可以在python中使用,也可以在其他语言中使用;
-
bs4:只可以在python语言中使用;
-
实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中;
-
通过调用BeautifulSoup对象中的相关属性或者方法进行标签定位和数据提取;
需要安装两个三方模块:
-
pip install bs4 (BeautifulSoup对象存在于bs4这个模块中)
-
pip install lxml (解析器)
-
xpath(重点):通用性最强;
2、数据解析的原理:
-
聚焦爬虫解析的局部文本内容,都会在标签之间或者标签对应的属性中进行存储;
-
进行指定标签的定位;
-
标签或标签对应的属性值中存取的数据值进行提取(解析);
3、聚焦爬虫相对于通用爬虫的编码流程会多增加一条:
-
指定url
-
发起请求
-
获取响应数据
-
数据解析
-
持久化存储
4、xpath解析:最常用且最便捷高效得一种解析方式,通用性也好:
-
xpath解析原理:
-
实例化一个etree对象,需要将被解析得页面源码数据加载到该对象中;
-
调用etree对象中得xpath方法,结合xpath表达式实现表得定位+内容得捕获;
-
环境的安装:
-
pip install lxml
-
如何实例化一个etree对象:
-
将本地的html文档中的源码数据加载到etree对象中:etree.parse(filePath)
-
将互联网上获取到的源码数据加载到etree对象中:etree.HTML(page_text)
-
使用的时候:et.xpath('xpath表达式')
-
xpath表达式:
-
/:标识从根节点开始定位,且单/表示一个层级;
-
//:表示多个层级,可以表示从任意位置开始定位;
-
属性定位:tag[@attrName='attrValue'],例如://div[@class='song'];
-
索引定位:例如://div[@class='song']/p[3],注意:这里的索引是从1开始的;
-
获取文本内容:
-
/text() :获取的是标签中直系的文本内容,返回值为数组,我们一般取索引为[0]位置的值;
-
//text() :获取的是标签中所有的文本内容,包括非直系的,返回值为数组;
-
获取属性值:
-
/@attrName : 获取某个标签的属性值,例如://div[@class='song']/img/@src;
-
xpath补充:xpath表达式可以使用 | 或连接符进行拼接:
all_list = tree.xpath('//div[@class="bottom"]/ul/li/a | //div[@class="bottom"]/ul/div[2]/li/a') # 通过这样的可拼接特性,xpath表达式就变得更加的强大!
二、实战小功能案例 — 58同城二手车图片(正则解析)
1、打开网站进行分析:https://sh.58.com/ershouche/
我们可以得到如下结论:
所有的图片都被包裹在一个class = "info_pic" 的<img>标签中;
上面定位出来的img标签中的 data-original 属性就是图片缩略图的url:
如果将上面的缩略图url进行截取,得到的就是大图的url:
2、有了上面的核心分析结论后,我们就直接开始coding编码吧:
import requests import re import os if __name__ == '__main__': # 先准备一个文件夹,保存所有的图片 if not os.path.exists('./output/58pics'): os.mkdir('./output/58pics') # 准备UA伪装 headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36' } # 设置一个通配的url模板字符串 temp_url = 'https://sh.58.com/ershouche/pn%d/' # 提前分析定义好正则表达式(使用.*?进行通配,\进行转义,(.*?)中的内容将是我们最终获得到的内容) ex = '<div class="info--pics">.*?data-original="(.*?)\?.*?</div>' # 正式干活,虽然页面显示有70页,但是我们只测试个5页即可 for pageNum in range(1, 6): real_url = temp_url % pageNum response_text = requests.get(real_url, headers=headers).text img_url_list = re.findall(ex, response_text, re.S) print(img_url_list, "图片列表...") # 下载img_url对应的图片到本地 for img_url in img_url_list: # 取/分割的最后一段为图片名称,确保不重复 img_name = str(img_url).split("/")[-1] # 发起请求,获得的数据为二进制数据,所以得用.content获取 img_data = requests.get(img_url, headers=headers).content # 将img_data数据存储到文件,注意mode为‘wb’,因为存储的是二进制数据,且不需要指定encoding with open("./output/58pics/" + img_name, 'wb') as fp: fp.write(img_data) print(img_name, "下载成功...")
3、我们运行程序进行测试:
查看最终下载到的图片:
非常Nice! (#^.^#)
三、实战小功能案例 — 爬取《三国演义》所有章节标题和内容(bs4解析)
1、安装bs4、lxml模块:
# 如果报错的话,检查是不是开着vpn pip install bs4 pip install lxml
2、浏览器访问网站:https://www.shicimingju.com/book/sanguoyanyi.html
爬取思路:
-
首先访问首页,可以轻松获得所有的章节标题:https://www.shicimingju.com/book/sanguoyanyi.html
-
每一个章节都能拼接出每一章节详情页的url:https://www.shicimingju.com/book/sanguoyanyi/1.html
-
再从每一个详情页中解析出正文内容;
-
页面标签的层级关系,class = 'book-mulu' 的div标签 > ul >li > a标签
3、直接开始coding编码:
import requests from bs4 import BeautifulSoup import os if __name__ == '__main__': if not os.path.exists('./output/sanguo'): os.mkdir('./output/sanguo') # 准备UA伪装 headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36' } # 设置url模板 index_url = 'https://www.shicimingju.com/book/sanguoyanyi.html' detail_base_url = 'https://www.shicimingju.com' # 开始干活 # 1、获取首页源码 index_response = requests.get(index_url, headers=headers) index_response.encoding = 'utf-8' index_text = index_response.text # 实例化BeautifulSoup对象 index_soup = BeautifulSoup(index_text, 'lxml') # 解析出章节标题和详情页的url li_list = index_soup.select('.book-mulu > ul > li') # 2、提前准备好一个文件,这样每一次直接追加即可: fp = open('./output/sanguo/三国演义.txt', 'w', encoding='utf-8') # 3、处理首页的soup元素,并发起详情页的请求 for li in li_list: # 直接a.string获取a标签中的文本作为title title = li.a.string detail_url = detail_base_url + li.a['href'] # 对详情页发起请求,并解析出章节内容 detail_response = requests.get(detail_url, headers=headers) detail_response.encoding = 'utf-8' detail_text = detail_response.text detail_soup = BeautifulSoup(detail_text, 'lxml') content_tag = detail_soup.find('div', class_='chapter_content') # 将title和正文全部写入到提前准备好的fp fp.write(title + ':\n' + content_tag.text + '\n') print(title, ':章节下载完成')
4、运行程序,测试结果:
查看《三国演义.txt》文本文件:
非常Nice,没毛病,老铁!o(* ̄︶ ̄*)o
四、实战小功能案例 — 4K图片解析下载(解决编码乱码用例)(xpath解析)
1、打开网址对页面结构进行分析:https://pic.netbian.com/4kmeinv/
所有的图片都被包裹在 //ul[class=clearfix] -> li -> a -> img标签中;
src属性中是图片的url链接,alt中是图片的名称;
2、话不多说,直接coding编码:
import requests from lxml import etree import os if __name__ == '__main__': if not os.path.exists('./output/4kpics'): os.mkdir('./output/4kpics') # 准备UA伪装 headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36' } url = 'https://pic.netbian.com/4kmeinv/' base_url = 'https://pic.netbian.com/' # 开始干活 response = requests.get(url, headers=headers) resp_text = response.text # 获得etree对象 et = etree.HTML(resp_text) li_list = et.xpath('//ul[@class="clearfix"]/li') for li in li_list: img_url = li.xpath('./a/img/@src')[0] img_name = li.xpath('./a/img/@alt')[0] # 由于纯在乱码的问题,我们可以使用一个很常用的方式进行重新编码解码 new_img_name = img_name.encode('iso-8859-1').decode('gbk') img_data = requests.get(base_url+img_url, headers=headers).content with open('./output/4kpics/'+new_img_name+'.jpg', 'wb') as fp: fp.write(img_data) print(new_img_name, "下载完成....")
3、测试,查看结果:
看下载好的图片:
Very Nice! (●'◡'●)