目录
1、数据解析原理概述
解析的局部文本内容都会在标签之间或者标签对应的属性中进行存储。
- 进行指定的标签定位;
- 标签或者标签中对应的属性中存储的数据进行提取(解析)
2、数据解析的分类
- 正则
- bs4
- xpath(*****)
3、聚焦爬虫
爬取页面中指定的页面内容。
编码流程:
- 指定url
- 发起请求
- 获取响应数据
- 数据解析
- 持久化存储
4、文件写入形式
- ‘r’:只读。该文件必须已存在。
- ‘r+’:可读可写。该文件必须已存在,写为追加在文件内容末尾。
- ‘rb’:表示以二进制方式读取文件。该文件必须已存在。
- ‘w’:只写。打开即默认创建一个新文件,如果文件已存在,则覆盖写(即文件内原始数据会被新写入的数据清空覆盖)。
- ‘w+’:写读。打开创建新文件并写入数据,如果文件已存在,则覆盖写。
- ‘wb’:表示以二进制写方式打开,只能写文件, 如果文件不存在,创建该文件;如果文件已存在,则覆盖写。
- ‘a’:追加写。若打开的是已有文件则直接对已有文件操作,若打开文件不存在则创建新文件,只能执行写(追加在后面),不能读。
- ‘a+’:追加读写。打开文件方式与写入方式和'a'一样,但是可以读。需注意的是你若刚用‘a+’打开一个文件,一般不能直接读取,因为此时光标已经是文件末尾,除非你把光标移动到初始位置或任意非末尾的位置。
5、数据解析的详解及实战
案例1:正则解析爬取页面所有图片
#conding:utf-8
##需求:爬取今日头条文章中的所有图片
import requests,re,os
if __name__ == '__main__':
#创建一个文件夹,保存所有的图片
if not os.path.exists('./图片采集'):
os.mkdir('./图片采集')
url = 'https://www.toutiao.com/article/7133370308483875332/?log_from=e4be24a887381_1662889167393'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0',
'cookie':'__ac_nonce=0631da83e00da50e351b1; msToken=jJMUn7b31BeJ4-2wwIsjy5Sbdtwb_3h_AAjUoneFz_SVcBEtdiFuFHZMqZW3aTkC-lHww6klWDmeBS-AJN6Fm1sF34Bj69IlBqESGh4AWT__; __ac_signature=_02B4Z6wo00f01b9noSgAAIDAoyQflJ3BRGm.VqWAAAzF2d; MONITOR_WEB_ID=5c0feb10-ec7f-44c4-8082-5e7bee3cb1b5; ttwid=1%7CkuDq-8ovtRvlQdoL5pwn7hMReI9GwRZuvnB5_6X_lig%7C1662889168%7C952a47eeec11c4eeb583ec4b9ef017d50c8abce4fd06cac127421209717e2449; tt_webid=7142049544879900191; ttcid=21315e87fadc484b8bc757825b9c745128; local_city_cache=%E6%B7%B1%E5%9C%B3; csrftoken=58f033666f965f462ac0e09657d6a1a2; _tea_utm_cache_24=undefined; s_v_web_id=verify_l7x4l0mj_8KRLiQXq_IXgH_4N2B_BBI1_3YrgSk6ESqDX; __feed_out_channel_key=gallery; tt_scid=WMQ2X.0H0YOTnk.cS5jnNnlqCHnlJkgQx5PK481GNwOV3VSvBRiISQprxOuWcf0U492d'
}
#使用通用爬虫对url对应的一整张页面进行爬取
page_text = requests.get(url=url,headers=headers).text
#print(page_text)
#使用聚焦爬虫将页面中所有的图片进行解析/提取
ex = '<img src="(.*?)" img_width.*?>'
img_src_list = re.findall(ex,page_text,re.S)
#print(img_src_list)
#请求到的图片进行二进制处理
for src in img_src_list:
src = src.replace('\n','')
img_data = requests.get(url=src,headers=headers).content
img_name = src.split('=')[-1]
#图片存储的路径
img_path = f'./图片采集/{img_name}.jpg'
with open(img_path,'wb') as f:
f.write(img_data)
print(img_name,'采集成功')
注:正则表达式一些可选标志修饰符
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解 |
正则表达式中,“.”的作用是匹配除“\n”以外的任何字符,也就是说,它是在一行中进行匹配。这里的“行”是以“\n”进行区分的。a字符串有每行的末尾有一个“\n”,不过它不可见。
如果不使用re.S参数,则只在每一行内进行匹配,如果一行没有,就换下一行重新开始,不会跨行。而使用re.S参数以后,正则表达式会将这个字符串作为一个整体,将“\n”当做一个普通的字符加入到这个字符串中,在整体中进行匹配。
案例2、bs4进行数据解析
0x01.原理:
- 实例化一个BeautifulSoup对象,并且将页面源代码数据加载到该对象中.(from bs4 import BeautifulSoup)
- 通过调用BeautifulSoup对象中相关的属性或者方法进行标签定位和数据提取
0x02.对象实例化:
- 将本地的html文档中的数据加载到该对象中:
fp = open('./test.html','r',encoding='utf-8')
soup = BeautifulSoup(fp,'lxml')
- 将互联网上获取的页面源码加载到该对象中:
page_text = response.text
soup = BeautifulSoup(page_text,'lxml')
0x03.用于数据解析的方法和属性:
- soup.tagname:返回的是文档中第一次出现tagname对应的标签;
- soup.find():等同于soup.tagname,但他还可以属性定位:soup.find('div',class_='***')(注:class要接个下划线才是名称,否则为关键字)
- soup.find_all('tagname'):找出符合要求的所有标签;
- select:参数当中可以放置一些选择器,返回的是一个列表—>select('某种选择器(id,class,标签...)'),例如:①、select('.tang > ul > li > a'),>表示的是一个层级,②、select('.tang > ul > a')空格表示的是多个层级,因此①结果等同于②;
0x04.获取标签之间的文本数据——>soup.a.text/string/get_text(),text/get_text()可以获取某一个标签中所有的文本内容,string只可以获取该标签下的直系文本内容
0x05.获取标签中的属性值——>soup.a['href']
0x06.案例:
#conding:utf-8
##需求:抓取古文网站论语
import requests,os
from bs4 import BeautifulSoup
if __name__ == '__main__':
if not os.path.exists('./书籍采集'):
os.mkdir('./书籍采集')
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0'
}
url = 'https://so.gushiwen.cn/guwen/book_46653FD803893E4F75696240258265D2.aspx'
page_text = requests.get(url=url,headers=headers).text
#print(page_text)
#实例化个对象
soup = BeautifulSoup(page_text,'lxml')
tag_list = soup.select('.bookcont > ul > span')
#print(tag_list)
fp = open('./书籍采集/论语.txt','w',encoding='utf-8')
#解析章节标题和详情页url
for span in tag_list:
title = span.a.string
#print(title)
detail_url = span.a['href']
#print(detail_url)
#对详情页发起请求解析章节内容
detail_page_text = requests.get(url=detail_url,headers=headers).text
#print(detail_page_text)
#解析出详情页中相关的章节内容
detail_soup = BeautifulSoup(detail_page_text,'lxml')
div_tag = detail_soup.find('div',class_="contson")
#解析章节内容
conten = div_tag.text
#print(conten)
#持久化存储
fp.write(title+conten+'\n')
print(title,'采集成功')
案例3、xpath数据解析
0x01.原理:
- 实例化一个etree对象,并且将页面源代码数据加载到该对象中.(from lxml import etree)
- 通过调用etree对象中xpath方法结合xpath表达式实现标签的定位和内容捕获,
0x02.对象实例化:
- 将本地的html文档中的数据加载到etre对象中:etree.parse(filepath)
- 将互联网上获取的页面源码加载到etree对象中:etree.HTML(page_text)
0x03.xpath表达式:
- /:表示的是从根节点开始定位,表示的是一个层级。
- //:表示的是多个层级,表示从任意位置开始定位。
- 属性定位:格式为:tag[@attrName='value'],例://div[@class=’song‘]
- 索引定位: 索引是从1开始的。例://div[@class='song']/p[3]
- 取文本:①、/text() 获取的是标签中直系的文本内容;②、//text()获取的是非直系的文本内容(所有文本内容)
- 取属性:/@attrName:直接/@加上属性名称(eg:img/@src)
0x04.实例1:爬取58二手房中的房源信息
#conding:utf-8
import requests
from lxml import etree
##需求:爬取58二手房中的房源信息
if __name__ == '__main__':
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0'
}
#爬取页面源码
url = 'https://sz.58.com/ershoufang/'
page_text = requests.get(url=url,headers=headers).text
#数据解析
tree = etree.HTML(page_text)
list = tree.xpath('//section[@class="list"]/div')
#print(list)
fp = open('58二手房信息.txt','w',encoding='utf-8')
for div in list:
#局部解析,注:局部解析以.开头
title = div.xpath('.//div[@class="property-content-title"]/h3/text()')[0]
print(title)
fp.write(title+'\n')
实例2:爬取图片
#conding:utf-8
import requests,os
from lxml import etree
##需求:解析下载图片数据
if __name__ == '__main__':
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0'
}
#获取页面源码
url = 'http://pic.netbian.com/4kmeinv/'
response = requests.get(url=url,headers=headers)
#response.encoding = 'utf-8'
page_text = response.text
#数据解析
tree = etree.HTML(page_text)
li_list = tree.xpath('//div[@class="slist"]//li')
#创建一个文件夹,保存所有的图片
if not os.path.exists('./图片采集'):
os.mkdir('./图片采集')
for li in li_list:
img_src = 'http://pic.netbian.com' + li.xpath('./a/img/@src')[0]
img_name = li.xpath('./a/img/@alt')[0] + '.jpg'
#通用处理中文乱码解决方案
img_names = img_name.encode('iso-8859-1').decode('gbk')
#print(img_names,img_src)
img = requests.get(url=img_src,headers=headers).content
img_path = '图片采集/' + img_names
with open(img_path,'wb') as fp:
fp.write(img)
print(img_names+'下载成功')
实例3:解析全国城市名称
#conding:utf-8
import requests
from lxml import etree
##需求:爬取网站中全国城市名称:https://www.aqistudy.cn/historydata/
if __name__ == '__main__':
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0'
}
#获取页面源码
url = 'https://www.aqistudy.cn/historydata/'
page_text = requests.get(url=url,headers=headers).text
#数据解析
tree = etree.HTML(page_text)
# hot_city_list = tree.xpath('//div[@class="bottom"]/ul/li')
# all_city_names = []
# for li in hot_city_list:
# hot_city_names = li.xpath('./a/text()')[0]
# all_city_names.append(hot_city_names)
# other_city_list = tree.xpath('//div[@class="bottom"]/ul/div[2]/li')
# for li in other_city_list:
# other_city_names = li.xpath('./a/text()')[0]
# all_city_names.append(other_city_names)
# print(all_city_names,len(all_city_names))
#利用|将者结合
all_city_list = tree.xpath('//div[@class="bottom"]/ul/li/a | //div[@class="bottom"]/ul/div[2]/li/a')
all_city_names = []
for a in all_city_list:
all_city_name = a.xpath('text()')
all_city_names.append(all_city_name)
print(all_city_names,len(all_city_names))
实例4:爬取站长素材中免费简历模板
#conding:utf-8
import requests,os
from lxml import etree
if __name__ == '__main__':
if not os.path.exists('./简历模板'):
os.mkdir('./简历模板')
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0'
}
#获取首页页面源码
for page in range(1,6):
if page == 1:
url = 'https://sc.chinaz.com/jianli/free.html'
else:
url = 'https://sc.chinaz.com/jianli/free_{}.html'.format(page)
page_text = requests.get(url=url,headers=headers).text
#对首页进行数据解析
tree = etree.HTML(page_text)
div_list = tree.xpath('//div[@id="main"]/div/div')
for div in div_list:
#获取首页简历模板下载地址
muban_url = 'https:' + div.xpath('./a/@href')[0]
#print(muban_url)
#获取某一简历模板页面下载地址页面源码
response = requests.get(url=muban_url,headers=headers)
response.encoding = 'utf-8'
reload_text = response.text
#print(reload_text)
#数据解析某一简历模板页面
_tree = etree.HTML(reload_text)
down_list = _tree.xpath('//div[@class="clearfix mt20 downlist"]/ul/li[1]/a')
title_list = _tree.xpath('//div[@class="bread clearfix"]/a[3]')
#print(_div_list)
#获取简历模板地址+名称
for a in title_list:
title = a.xpath('./@title')[0]
#print(title)
for a in down_list:
down_add = a.xpath('./@href')
#对简历模板发起请求
for down_url in down_add:
muban_data = requests.get(url=down_url,headers=headers).content
#print(muban_data)
#持久化存储
filepath = f'简历模板/{title}.rar'
with open(filepath,'wb') as fp:
fp.write(muban_data)
print(title+'下载成功!!!')