爬虫中的数据解析

  • 肯德基
#爬取单页的数据
import requests
headers = {
    'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
}
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
data = {
    "cname": "",
    "pid": "",
    "keyword": "天津",
    "pageIndex": "1",
    "pageSize": "10"
}
#post请求携带请求参数使用data这个参数
response = requests.post(url=url,headers=headers,data=data)

data = response.json()
for dic in data['Table1']:
    city = dic['cityName']
    address = dic['addressDetail']
    print(city,address)
  • 下厨房:
import requests

#请求头
headers = {
    'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
}
title = input('请输入菜名:')
params = {
    'keyword':title,
    'cat':'1001'
}
#1.指定url
url = 'https://www.xiachufang.com/search/'

#2.发起请求
response = requests.get(url=url,headers=headers,params=params)
#处理乱码
response.encoding = 'utf-8' #gbk
# 搜索:charset

#3.获取响应数据
page_text = response.text

#4.持久化存储
fileName = title + '.html'
with open(fileName,'w') as fp:
    fp.write(page_text)

数据解析

何为数据解析

  • 概念:可以将爬取到的数据中的指定想要的数据进行单独提取。

  • 作用:可以实现聚焦爬虫。

  • 数据解析通用原理:

    • 在一张页面源码中,想要爬取的数据是存在于相关的html的标签中。
    • 可以将指定的标签进行定位,然后提取该标签中或者标签属性中存储的数据即可。
  • 聚焦爬虫编码流程:

    • 指定url
    • 发起请求
    • 获取响应数据
    • 数据解析
    • 持久化存储
  • python中可以实现数据解析的技术:

    • xpath(重要、常用和便捷)
    • Bs4(自行了解学习)
    • re正则
    • pyquery(自行了解学习)
    • json

数据解析的主流策略

xpath(重点)

环境安装:pip install lxml

xpath解析的编码流程:

  • 1.创建一个etree类型的对象,然后把即将被解析的页面源码数据加载到该对象中。
  • 2.调用etree对象中的xpath函数,让其结合着不同形式的xpath表达式进行标签定位和数据提取。

xpath表达式基础操作:

  • 搭建一个实验环境:新建一个test.html文件,然后文件中写入下面内容:
<html lang="en">
<head>
	<meta charset="UTF-8" />
	<title>测试bs4</title>
</head>
<body>
	<div>
		<p>百里守约</p>
	</div>
	<div class="song">
		<p>李清照</p>
		<p>王安石</p>
		<p>苏轼</p>
		<p>柳宗元</p>
		<a href="http://www.song.com/" title="赵匡胤" target="_self">
			<span>this is span</span>
		宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a>
		<a href="" class="du">总为浮云能蔽日,长安不见使人愁</a>
		<img src="http://www.baidu.com/meinv.jpg" alt="" />
	</div>
	<div class="tang">
		<ul>
			<li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li>
			<li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li>
			<li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li>
			<li><a href="http://www.sina.com" class="du">杜甫</a></li>
			<li><a href="http://www.dudu.com" class="du">杜牧</a></li>
			<li><b>杜小月</b></li>
			<li><i>度蜜月</i></li>
			<li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li>
		</ul>
	</div>
</body>
</html>
  • 学习不同形式的xpath表达式(重点)
from lxml import etree  
# 提取本地数据
# 1.创建一个etree类型的工具/对象,把被解析的页面源码数据加载到该对象中
tree = etree.parse('./05-数据解析之本地数据解析.html')  # parse是解析本地的html文件里的内容;HTML是解析爬虫爬到的页面源码数据。parse加载的是一个的文件,可以将文件里的数据放到解析对象当中。而HTML可以将字符串形式的页面源码数据放到解析对象当中。所以在爬虫里面用的是HTML。./表示在同一目录下
# 2.调用etree对象的xpath函数,结合不同xpath表达式进行标签定位和数据提取
# 标签定位的xpath表达式:
# 定位meta标签
# ret = tree.xpath('/html/head/meta')[0]
# ret = tree.xpath('//meta')[0]  # 从相对位置定位meta标签。<Element meta at 0x1177e613d80>
# 定位所有的div标签
# ret = tree.xpath('//div')
# 索引定位:想要定位到第一个div标签(下标是从1开始)
# ret = tree.xpath('//div[1]')
# 属性定位:定位到class属性值为song的div标签.//tagName[@attrName="attrValue"]。tagName为标签名。attrName为属性名。attrValue为字符串形式的属性值。
# ret = tree.xpath('//div[@class="song"]')
# ret = tree.xpath('//a[@class="du"]')[0]
# 层级标签:定位所有li标签下的a标签
# ret = tree.xpath('//div[@class="tang"]/ul/li/a')
# ret = tree.xpath('//div[@class="tang"]//li/a')  # 将div下边的li标签(可以是div的直系子标签,也可以不是直系子标签)全部取出,//指多个层级。
# print(ret)

# 数据提取:
    # 提取标签内的文本内容
# ret = tree.xpath('//a[@id="feng"]/text()')[0]  # 提取a标签中的文本内容
# ret = tree.xpath('//div[@class="song"]//text()')  # /text()提取标签直系的文本内容;//text()提取标签下所有的文本内容。
# print(ret)
    # 提取标签的属性值内容:语法://tagName/@attrName。tagName定位到的标签,attrName属性名
# ret = tree.xpath('//img/@src')[0]
# print(ret)

# 可以做标签定位,可以提取直系和非直系内容,可以提取标签的属性值内容。xpath就学会了。

案例应用:碧血剑文本爬取

import requests
from lxml import etree

# 1.指定url
url = 'https://bixuejian.5000yan.com/'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36'
}

# 2.发起请求(携带请求参数)
response = requests.get(url=url, headers=headers)
# 处理乱码
response.encoding = 'utf-8'  # 或gbk,试试,一般不需要,出现乱码时在此加上这行代码。
# 搜索:charset

# 3.获取响应数据
page_text = response.text

# 数据解析:解析章节的标题&详情页的url
# 创建一个etree类型的工具/对象,把被解析的页面源码数据加载到该对象中
tree = etree.HTML(page_text)  # parse是解析本地的html文件里的内容;HTML是解析爬虫爬到的页面源码数据。parse加载的是一个的文件,可以将文件里的数据放到解析对象当中。而HTML可以将字符串形式的页面源码数据放到解析对象当中。所以在爬虫里面用的是HTML。

# li_list列表中存储的是xpath表达式定位到的每一个li标签
# 调用etree对象的xpath函数,结合不同xpath表达式进行标签定位和数据提取
li_list = tree.xpath('/html/body/div[2]/div[1]/main/ul/li')  # xpath地址可以复制出来的:定位到Elements选项卡中->点一下左上角的小箭头(Elements同一行)(Ctrl+Shift+C)->鼠标移到对应页面目标并点击一下->鼠标移到Elements下的框中标出阴影的地方单击右键(这里只是定位到一个目标标签,要定位相同一组的目标标签,要定位在此标签的上一级li标签或上上一级标签ul标签,此处定位在此标签的上上一级ul标签,)->复制->复制xpath->在pycharm中粘贴路径—>手动输入此标签的上一级标签li标签。

# fp = open('xiaoshuo.txt', 'w', encoding='utf-8')
with open('../pydirectory/xiaoshuo.txt', 'w', encoding='utf-8') as fp:
    for li in li_list:
        # 局部解析:只可以解析li标签内部的局部标签
        # 调用etree对象的xpath函数,结合不同xpath表达式进行标签定位和数据提取
        title = li.xpath('./a/text()')[0]  # 这个.表示的是xpath的调用者,也就是li标签。title是a标签里的文本内容,即小说的标题。text()解析的是文本内容。
        detail_url = li.xpath('./a/@href')[0]  # detail_url是标题详情页的url。@href解析的是a标签的href属性值。
        # print(title, detail_url)
        # 对详情页的url发起请求,获取详情页的页面源码数据
        detail_response = requests.get(url=detail_url, headers=headers)
        detail_response.encoding = 'utf-8'
        detail_page_text = detail_response.text  # 详情页的页面内容
        # 对详情页进行数据解析:章节内容
        detail_tree = etree.HTML(detail_page_text)
        content = detail_tree.xpath('/html/body/div[2]/div[1]/main/section/div[1]//text()')  # 返回一个列表。
        # 将content列表转换成一个完整的字符串(小说的内容)
        content = ''.join(content).strip()  # .join(content)将列表转换成字符串,strip()去除空格。

        # 小说的标题有了:title;小说的内容有了:content;下面就是持久化存储:

        # 4.持久化存储
        fp.write(title + ':' + content + '\n')
        print(title, ':章节下载保存成功!')

简历模版下载:https://sc.chinaz.com/jianli/free.html

  • 下载当前页所有的建立模板

    • 简历名称+简历的下载链接
    • 根据简历的下载链接 下载简历文件
    • 根据下载地址下载的压缩包,压缩包是二进制的数据
import requests
from lxml import etree

# 1.指定url

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36'
}

# 2.发起请求(携带请求参数),获取首页的页面源码数据。
for page in range(1, 6):
    if page == 1:
        url = 'https://sc.chinaz.com/jianli/free.html'
    else:
        url = f'https://sc.chinaz.com/jianli/free_{page}.html'
    print(f'正在爬取{page}页数据.......')

    response = requests.get(url=url, headers=headers)  # 第一次发请求,相当于进入首页界面。
    response.encoding = 'utf-8'  # 处理乱码
    # 搜索:charset

    # 3.获取响应数据
    page_text = response.text
    # 解析首页的页面源码数据:解析简历的名称&详情页的url
    tree = etree.HTML(page_text)  # 创建一个etree类型的工具/对象,把被解析的页面源码数据加载到该对象中
    # 调用etree对象的xpath函数,结合不同xpath表达式进行标签定位和数据提取
    # div_list列表中存储的是xpath表达式定位到的每一个div标签
    div_list = tree.xpath(
        '//*[@id="container"]/div')  # 调用etree对象的xpath函数,结合不同xpath表达式进行标签定位和数据提取,xpath地址可以复制出来的:定位到Elements选项卡中->点一下左上角的小箭头(Elements同一行)(Ctrl+Shift+C)->鼠标移到对应页面目标并点击一下->鼠标移到Elements下的框中标出阴影的地方单击右键(这里只是定位到一个目标标签,要定位相同一组的目标标签,要定位在此标签的上一级div标签或上上一级标签div标签,此处定位在此标签的上上一级div标签,)->复制->复制xpath->在pycharm中粘贴路径—>手动输入此标签的上一级标签div标签。

    for div in div_list:
        # 局部解析:只可以解析div标签内部的局部标签
        title = div.xpath('./p/a/text()')[
            0]  # 这个.表示的是xpath的调用者,也就是div标签。title是p标签里a标签的文本内容,即简历的标题。text()解析的是文本内容。这不能直接复制xpath地址,那样只能固定获取一个简历,要用./表示遍历到的各个节点(即各个div标签)下的p标签里a标签的内容。
        detail_url = div.xpath('./a/@href')[0]  # detail_url是标题详情页的url。@href解析的是a标签的href属性值。
        # print(title, detail_url)
        # 对详情页的url发起请求,获取详情页的页面源码数据
        detail_response = requests.get(url=detail_url, headers=headers)  # 第二次发请求,相当于进入单独模板界面。
        # detail_response.encoding = 'utf-8',看情况,如果无乱码就不写。
        detail_page_text = detail_response.text  # 详情页的页面内容
        # 对详情页进行数据解析:解析出下载地址
        detail_tree = etree.HTML(detail_page_text)  # 解析详情页
        download_url = detail_tree.xpath('//*[@id="down"]/div[2]/ul/li/a/@href')[0]  # 用xpath解析出下载地址
        # 对下载地址发起请求,下载对应的简历压缩包数据
        data = requests.get(download_url, headers=headers).content  # 相当于点击下载链接进行下载。# 第三次发请求,相当于进入下载界面进行下载。.content是把下载的源代码转成二进制数据。因为压缩包(.rar)是二进制数据。
        file_name = '../pydirectory/简历模板/' + title + '.rar'  # '../pydirectory/简历模板/'后面加/表示简历模板是文件夹名,不加/就和title结合成文件名。
        with open(file_name, 'wb') as fp:
            fp.write(data)
            print(title, ":下载保存成功!")

图片数据爬取:

  • http://pic.netbian.com/4kmeinv/

  • 将爬取到的图片存储到指定的文件夹中

  • 抓取详情页大图

  • 爬取多页

  • # 图片数据爬取
    
    # 设置请求参数
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36'
    }
    
    # 发起请求,获取首页的页面源码数据。
    
    for page in range(1, 3):
        if page == 1:
            url = 'http://pic.netbian.com/4kmeinv/'
        else:
            url = f'http://pic.netbian.com/4kmeinv/index_{page}.html'
        print(f'正在爬取{page}页数据.......')
        # 对首页进行页面源码数据的获取
        response = requests.get(url=url, headers=headers)  # 第一次发请求,相当于进入首页界面。
        # print(response.apparent_encoding)  # 获取网页编码
        response.encoding = 'gbk'  # 处理乱码
        page_text = response.text
    
        # 数据解析:图片名字和图片详情页url
        tree = etree.HTML(page_text)  # 注意这不能加引号,否则后面获取不了数据
        li_list = tree.xpath('//*[@id="main"]/div[3]/ul/li')
        for li in li_list:
            li.xpath('./a/@href')
            title = li.xpath('./a/b/text()')[0]
            detail_url = 'http://pic.netbian.com' + li.xpath('./a/@href')[0]
    
            # 对图片的详情页发起请求,获取详情页的页面源码数据
            detail_response_text = requests.get(url=detail_url, headers=headers).text  #第二次发请求,相当于进入大图界面。这是拿详情页面的源码数据。
            # 数据解析,获取详情页的大图地址
            detail_tree = etree.HTML(detail_response_text)
            img_src = 'http://pic.netbian.com'+detail_tree.xpath('//*[@id="img"]/img/@src')[0]  # 注意是@src不是@href。
            # 对大图地址发请求,下载图片。
            img_data = requests.get(img_src, headers=headers).content  # 第三次发请求,相当于点击下载链接下载图片。content把源码数据转成二进制数据。下载到图片数据。
    
            img_path = '../pydirectory/4k图片/' + title + '.jpg'
            with open(img_path, 'wb') as fp:
                fp.write(img_data)
                print(title, ":下载保存成功!")
    

防盗链

  • 现在很多网站启用了防盗链反爬,防止服务器上的资源被人恶意盗取。什么是防盗链呢?

    • 从HTTP协议说起,在HTTP协议中,有一个表头字段:referer,采用URL的格式来表示从哪一个链接跳转到当前的网页或者文件。referer后面所存储的是url,这个url就可以表示当前请求的数据是从哪一个源头来的,referer采用的是用url的格式来表示从哪一个链接跳转到当前的网页或者文件。通俗理解就是:客户端的请求具体从哪里来,服务器可以通过referer进行溯源。一旦检测来源不是网页所规定的,立即进行阻止或者返回指定的页面。
  • 案例:抓取微博图片,url:http://blog.sina.com.cn/lm/pic/,将页面中某一组系列详情页的图片进行抓取保存,比如三里屯时尚女郎:http://blog.sina.com.cn/s/blog_01ebcb8a0102zi2o.html?tj=1

  • 注意:

    • 1.在解析图片地址的时候,定位src的属性值,返回的内容和开发工具Element中看到的不一样,通过network查看网页源码发现需要解析real_src的值。

    • 2.直接请求real_src请求到的图片不显示,加上Refere请求头即可

      • 哪里找Refere:抓包工具定位到某一张图片数据包,在其requests headers中获取
    • import requests
      from lxml import etree
      headers = {
          'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36',
          "Referer": "http://blog.sina.com.cn/",
      
      }
      url = 'http://blog.sina.com.cn/s/blog_01ebcb8a0102zi2o.html?tj=1'
      page_text = requests.get(url,headers=headers).text
      tree = etree.HTML(page_text)
      img_src = tree.xpath('//*[@id="sina_keyword_ad_area2"]/div/a/img/@real_src')
      for src in img_src:
          data = requests.get(src,headers=headers).content
          with open('./123.jpg','wb') as fp:
              fp.write(data)
          # break
      

      另一种思路写代码:

import requests
from lxml import etree

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36',
    'Referer': 'https://blog.sina.com.cn/s/blog_01ebcb8a0102zi2o.html?tj=1'
}

url = 'https://blog.sina.com.cn/s/blog_01ebcb8a0102zi2o.html?tj=1'

page_text = requests.get(url=url, headers=headers).text  # .text获取源码数据

tree = etree.HTML(page_text)
img_src_list = tree.xpath('//*[@id="sina_keyword_ad_area2"]/div/a/img/@real_src')  # 解析出图片地址
# requests.get(url=img_src_list[0], headers=headers)  # [0]对第一张图片发起请求。
count = len(img_src_list)  # 计算一下要下载的图片的张数。
i = 0
while i < count:
    n = 1
    data = requests.get(url=img_src_list[i], headers=headers).content  # [i]对第i张图片发起请求。
    img_path = '../pydirectory/三里屯图片/' + f'{i}' + '.jpg'  # f'{i}'下载的图片命名为'i.jgp'。
    with open(img_path, 'wb') as fp:
        fp.write(data)
        print(img_path, ':下载保存成功!')
    i += n

图片懒加载

  • url:https://sc.chinaz.com/tupian/meinvtupian.html
  • 爬取上述链接中所有的图片数据
  • 图片懒加载(异步加载):
    • 主要是应用在展示图片的网页中的一种技术,该技术是指当网页刷新后,先加载局部的几张图片数据即可,随着用户滑动滚轮,当图片被显示在浏览器的可视化区域范围的话,在动态将其图片请求加载出来即可。(图片数据是动态加载出来)。
    • 如何实现图片懒加载/动态加载?
      • 使用img标签的伪属性(指的是自定义的一种属性)(real_src,暂时保存图片真正的地址)。在网页中,为了防止图片马上加载出来,则在img标签中可以使用一种伪属性来存储图片的链接,而不是使用真正的src属性值来存储图片链接。(图片链接一旦给了src属性,则图片会被立即加载出来)。只有当图片被滑动到浏览器可视化区域范围的时候,在通过js将img的伪属性修改为真正的src属性(将src的值改为real_src保存的值),则图片就会被加载出来。src保存的不是真正的链接,为属性保存的是真正的链接。伪属性的命名不一定只是real_src,也可以是任意的命名。
  • 如何爬取图片懒加载的图片数据?
    • 只需要在解析图片的时候,定位伪属性的属性值即可。
# 图片数据爬取
import requests
from lxml import etree
# 设置请求参数
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36',
    'Referer': 'https://sc.chinaz.com/'
}
# 发起请求,获取首页的页面源码数据。
for page in range(1, 6):
    if page == 1:
        url = 'https://sc.chinaz.com/tupian/meinvtupian.html'
    else:
        url = f'https://sc.chinaz.com/tupian/meinvtupian_{page}.html'
    print(f'正在爬取{page}页数据.......')
    # 对首页进行页面源码数据的获取
    response = requests.get(url=url, headers=headers)  # 第一次发请求,相当于进入首页界面。
    # print(response.apparent_encoding)  # 获取网页编码
    response.encoding = 'utf-8'  # 处理乱码
    page_text = response.text
    # 数据解析:图片标题和图片详情页url
    tree = etree.HTML(page_text)  # 注意这不能加引号,否则后面获取不了数据。创建etree对象
    li_list = tree.xpath('/html/body/div[3]/div[2]/div')  # 调用xpath函数
    for li in li_list:
        li.xpath('./div/a/@href')
        detail_url = 'https://sc.chinaz.com' + li.xpath('./div/a/@href')[0]  # 拼接图片详情url
        title = li.xpath('./div/a/text()')[0]  # 解析图片标题
        # 对图片的详情页发起请求,获取详情页的页面源码数据
        detail_response_text = requests.get(url=detail_url, headers=headers).text  # 第二次发请求,相当于进入大图界面。这是拿详情页面的源码数据。.text把源码数据转为文本数据。
        # 数据解析,获取详情页的大图地址
        detail_tree = etree.HTML(detail_response_text)
        img_src = detail_tree.xpath('/html/body/div[3]/div[1]/div[2]/div[1]/div[1]/p/a/@href')[0]

        # 对大图地址发请求,下载图片。
        img_data = requests.get(img_src, headers=headers).content  # 第三次发请求,相当于点击下载链接下载图片。content把源码数据转成二进制数据。下载到图片数据。.content把源码数据转为二进制数据(图片)
        img_path = '../pydirectory/美女图片/' + title + '.jpg'
        with open(img_path, 'wb') as fp:
            fp.write(img_data)
            print(title, ":下载保存成功!")

posted @ 2023-10-30 21:06  氨糖  阅读(9)  评论(0编辑  收藏  举报