python爬虫二
数据解析
对于爬取到数据我们已经有了一定的了解,那么我们最终无论是要将这些数据可视化还是进行统一某种算法的数据分析,我们不可避免的都要将数据持久化存储(无论是文件形式还是数据库形式)可在这之前我们需要对数据进行进一步处理,因为我们爬取的页面数据有很大一部分是对我们来说没有什么用处的,所以在持久化之前我们要做的就是进行数据解析,将我们所需要的数据提取出来。
对于数据解析(也就是要获取我们所需要的数据)大部分人第一反应就是正则匹配,诚然我们对正则匹配更加熟悉,对全局的数据进行一定规则的筛选从而拿到我们所需的数据,其实在整个爬虫中re也是一种解决方法,在这里为大家总结了三种不同的解析方式分别是re,beautifulsoup解析与xpath解析,同时希望大家总结一个自己喜欢或者用的习惯,或者简便的数据解析方法
re正则匹配
如果你自学或者通过其他途径学习过python,那么正则匹配,也就是python中的re模块你必定是接触过的了,通过自定义一个规则来在数据中获取符合规则的字符串片段。在这里就不为大家进行re的详细介绍了,如果有不知道的小伙伴可以自行搜索一下,对正则有个基础的了解,接下来就用实例为大家举例一下re在爬虫中的数据解析
爬取图片网站的图片信息:目标地址站长素材http://sc.chinaz.com/tupian/rentiyishu.html(别问为什么是人体艺术,懂得都懂)
首先还是老规矩,我们对网页进行分析我们发现我们所需的数据统一在一个大的div标签下,内部嵌套了一堆小的div标签,而我们所需要的数据都在这个div下的image标签中,包括图片的名称和图片的实际链接,分析结束后我们可以得出我们需要图片的过程大概就是
1.爬取首页获取首页数据
2.根据首页数据进行数据解析拿到每个img的src和alt属性
3.对每个请求链接进行请求然后进行持久化存储
既然我们已经对步骤进行了分析那么代码的实现就简单多了
import re import requests import os dir_name = '人体艺术' if not os.path.exists(dir_name): os.mkdir(dir_name) headers = { "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36" } url = "http://sc.chinaz.com/tupian/rentiyishu.html" response = requests.get(url=url,headers=headers).text #拿到页面数据 re_rule = '<img alt="(.*?)" src="(.*?)">' #匹配规则 img_list=re.findall(re_rule,response) # 拿到所需数据返回一个列表,内部所有的元素都是一个个的元组 for i in img_list: img_data = requests.get(url=i[1],headers=headers).content #获取图片数据 with open('./人体艺术/%s'%i[0],'w') as f: #进行持久化存储 f.write(img_data)
我们通过这种方式得到了广大男性同胞喜闻乐见的一个文件夹,当然我们还是要将目光聚焦到re的使用上。
BeautifulSoup解析
通过上述re匹配的规则之后,我们发现re匹配的缺点很明显,首先来说页面中数据容易重复,我们很容易就会爬取到我们不需要的数据(当然如果你的正则写的足够详细这点也可以在一定程度上避免),其次就是如果我们需要匹配多处数据那么你就要根据页面书写多个正则匹配,很麻烦,所以接下来我们要介绍的就是更简单的方法。
(1)根据标签名查找
- soup.a 只能找到第一个符合要求的标签
(2)获取属性
- soup.a.attrs 获取a所有的属性和属性值,返回一个字典
- soup.a.attrs['href'] 获取href属性
- soup.a['href'] 也可简写为这种形式
(3)获取内容
- soup.a.string
- soup.a.text
- soup.a.get_text()
【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容
(4)find:找到第一个符合要求的标签
- soup.find('a') 找到第一个符合要求的
- soup.find('a', title="xxx")
- soup.find('a', alt="xxx")
- soup.find('a', class_="xxx")
- soup.find('a', id="xxx")
(5)find_all:找到所有符合要求的标签
- soup.find_all('a')
- soup.find_all(['a','b']) 找到所有的a和b标签
- soup.find_all('a', limit=2) 限制前两个
(6)根据选择器选择指定的内容
select:soup.select('#feng')
- 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
- 层级选择器:
div .dudu #lala .meme .xixi 下面好多级
div > p > a > .lala 只能是下面一级
【注意】select选择器返回永远是列表,需要通过下标提取指定的对象
soup在某种程度上不用我们在使用自定义的正则匹配,而是通过标签来选择我们所需要的元素
爬取目标三国演义,分析过程与上一个实例相同,这里就不在多做赘述
目标地址https://www.shicimingju.com/book/sanguoyanyi.html
#我们首先要安装相关包才能使用 pip install bs4 pip install lxml from bs4 import BeautifulSoup #导包 main_url = "https://www.shicimingju.com/book/sanguoyanyi.html" #对首页进行信息爬取 page_text = requests.get(main_url,headers=header).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 = 'https://www.shicimingju.com'+a['href'] page_detail_text = requests.get(detail_url,headers=header).text #进行详情页信息爬取 detail_soup = BeautifulSoup(page_detail_text,"lxml") content = detail_soup.find('div',class_="chapter_content").text #数据解析 fp.write(title+'\n'+content+'\n') #持久化存储 fp.close()
soup并不是我们所能接触的最简单的方式,大家可以去尝试在浏览器开发工具中当我们copy一个标签的时候,会出现copy xpath的选项,这个xpath就是一种在数据解析的时候一种xml格式的路径,所以接下来要介绍的就是我们最常用而且使用起来最为方便的一种数据解析方式 xpath
Xpath数据解析
xpath解析过程就是将数据进行实例化生成一个etree对象,通过调用封装好的方法属性来进行数据的检索与提取
属性定位:
#找到class属性值为song的div标签
//div[@class="song"]
层级&索引定位:
#找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a
//div[@class="tang"]/ul/li[2]/a
逻辑运算:
#找到href属性值为空且class属性值为du的a标签
//a[@href="" and @class="du"]
模糊匹配:
//div[contains(@class, "ng")]
//div[starts-with(@class, "ta")]
取文本:
# /表示获取某个标签下的文本内容
# //表示获取某个标签下的文本内容和所有子标签下的文本内容
//div[@class="song"]/p[1]/text()
//div[@class="tang"]//text()
取属性:
//div[@class="tang"]//li[2]/a/@href
这里我们就要使用到我们之前下载好的包lxml 来导入etree
我们就拿上一篇文章的最后一个实例来举例详解一下xpath是如何工作的
import requests headers = { "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36" } import os from lxml import etree dirName = 'girlLib' if not os.path.exists(dirName): os.mkdir(dirName) main_url = "http://pic.netbian.com/4kmeinv/" #访问主页面 response = requests.get(main_url,headers=header) response.encoding = "gbk" page_text =response.text tree = etree.HTML(page_text) #当解析网络数据的时候用.HTML,如果是本地文件则用.parse img_list = tree.xpath("//div[@class='slist']/ul/li/a/img")#获取对应标签 找到属性为slist的div标签取到线面ul标签,再取下面的li标签,以此类推,最后获得img标签,得到的是一个tree对象 for img in img_list: img_src = "http://pic.netbian.com"+img.xpath("./@src")[0] img_name = img.xpath("./@alt")[0]+".jpg" img_data = requests.get(img_src,headers=header).content # print(img_data) img_path = dirName+"/"+img_name with open(img_path,"wb") as f: f.write(img_data)
通过对三种数据解析方式的讲解你是否已经掌握?其实我们工作中和学习中使用的更多的是xpath方法,希望大家多多联系。