三 python爬虫之数据解析

1. requests模块实现数据爬取的流程

  • 指定url
  • 发起请求
  • 获取响应数据
  • 持久化存储
    在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指定数据解析。因为大多数情况下的需求,我们都会指定去使用聚焦爬虫,也就是爬取页面中指定部分的数据值,而不是整个页面的数据。因此,本次课程中会给大家详细介绍讲解三种聚焦爬虫中的数据解析方式。至此,我们的数据爬取的流程可以修改为:
  • 指定url
  • 发起请求
  • 获取响应数据
  • 数据解析
  • 持久化存储

2 python如何实现数据解析?

2.1正则表达式

案列:

# 2020-10-28
# 分页爬取糗事百科 热图版块所有图片
import requests
import  re
import  os
if __name__=="__main__":
    if not os.path.exists('./qiutu'):  #创建文件夹 判断是否存在 若不存在则创建
        os.mkdir('./qiutu')
        # ua伪装
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
    }
    # 指定url
    # url = 'https://www.qiushibaike.com/imgrank/'
    url = 'https://www.qiushibaike.com/imgrank/page/%d/'
    for PageNum in range(1,3):
        # 使用通用流程 爬取目标一整张页面
        new_url = format(url%PageNum)
        response = requests.get(url=new_url,headers=headers)
        page_text = response.text

        #使用聚焦爬虫对页面中的图片进行解析
        # < div class ="thumb" >
        # < a href = "/article/123725630" target = "_blank" >
        # < img src = "//pic.qiushibaike.com/system/pictures/12372/123725630/medium/RJFYAKHCS96PMWUO.jpg"
        # alt = "糗事#123725630" class ="illustration" width="100%" height="auto" >< / a >
        # < / div >
       #ex = '<div class ="thumb">.*?<img src="(.*?)" alt.*?</div>'  #正则表达式 错误写法多了一个class后空格
       # 上面的html代码 为为我们需要爬取的图片的标签 通过正则表达式 取出每张图片路径src
        ex = '<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
        img_src_list = re.findall(ex,page_text,re.S)
        #print(img_src_list)

        for src in img_src_list:   #遍历列表 通过src获取图片
            src= "https:"+src   #图片地址
            response = requests.get(url=src,headers=headers)
            ima_data = response.content
            img_name = src.split('/')[-1] #生成图片名称 如第一张 CHJY6LJ7Y00R9C18.jpg
            img_path = './qiutu/'+img_name  #生成存储每张图片的路径

            with open(img_path,'wb') as fp:
                fp.write(ima_data)
                print(img_name,'爬取完成')

2.2 bs4解析

如何实例化BeautifulSoup对象
from bs4 import BeautifulSoup
1、将本地的html文档中的数据加载到该对象中
fp=open(’./test.html’,‘r’,encoding=‘uft-8’)
soup=BeautifulSoup(fp,‘lxml’)
2、将互联网上获取的页面源码加载到该对象中
page_text=response.text
soup=BeautifulSoup(page_text,‘lxml’)

提供的用于数据解析的方法和属性:
(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选择器返回永远是列表,需要通过下标提取指定的对象

案例 爬取三国演义

# -*- coding: utf-8 -*-
import lxml
import requests
from bs4 import BeautifulSoup
if __name__ == '__main__':
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
    }
    #爬取首页信息
    url='http://www.shicimingju.com/book/sanguoyanyi.html'
    page_text=requests.get(url=url,headers=headers).text

    #在首页中解析出章节标题和详情页的url
    #1、实例化BeautifulSoup对象
    soup=BeautifulSoup(page_text,'lxml')
    #2、解析章节标题和url
    li_list = soup.select('.book-mulu > ul > li')
    #文本文件相关
    fp = open('./三国演义.txt','w',encoding='utf-8')
    for li in li_list:
        title=li.a.string
        detail_url='http://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+':'+'\n'+content+'\n')
        print(title,"获取成功")
    print("三国演义爬取完成")

2.3 xpath解析

(1)引入

xpath解析是我们在爬虫中最常用也是最通用的一种数据解析方式,由于其高效且简介的解析方式受到了广大程序员的喜爱。在后期学习scrapy框架期间,也会再次使用到xpath解析。

(2) 环境安装

pip install lxml

(3) 解析原理

  • 使用通用爬虫爬取网页数据
  • 实例化etree对象,且将页面数据加载到该对象中
  • 使用xpath函数结合xpath表达式进行标签定位和指定数据提取

(4) 常用xpath表达式

属性定位:
    找到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

etree对象实例化

  • 本地文件:tree = etree.parse(文件名)
    tree.xpath(“xpath表达式”)
  • 网络数据:tree = etree.HTML(网页内容字符串)
    tree.xpath(“xpath表达式”)

案列1 爬取58二手房信息

# 2020-10-31
import requests
from lxml import etree

if __name__ == '__main__':
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
    }
    url = 'https://huizhou.58.com/ershoufang/'
    page_text = requests.get(url=url, headers=headers).text
    tree = etree.HTML(page_text)
    #xpath表达式 获取所有li标签内容
    li_list = tree.xpath('//ul[@class="house-list-wrap"]/li')
    fp = open('58.txt','w',encoding='utf-8')
    for li in li_list:
        #获取li标签里的标题title  注意./是定位到当前li标签下的 一定要加点
        title = li.xpath('./div[2]/h2/a/text()')[0]
        price = li.xpath('./div[3]/p/b/text()')[0]
        t = title.replace("\u00a0", "")   #去掉空格
        print(t)
        fp.write(t+'-'+price+'\n')
    fp.close()

案例2 爬取图片

# 2020-10-31 需求 通过xpath 解析4k图片数据
import requests
from lxml import etree
import os
if __name__ == '__main__':
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
    }
    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('//ul[@clearfix]/li')  定位错误 导致li_list为空列表
    li_list = tree.xpath('//div[@class="slist"]/ul/li')
    # print(li_list)

    if not os.path.exists('./4kmm'):
        os.mkdir('./4kmm')

    for li in li_list:
        #获取每张图片地址src
        img_src ='http://pic.netbian.com/' + li.xpath('./a/img/@src')[0]
        #获取alt属性
        img_alt = li.xpath('./a/img/@alt')[0]
        img_name = img_alt+'.jpg'
        #通用处理乱码解决
        img_name = img_name.encode('iso-8859-1').decode('gbk')
        # print(img_name,img_src)
        #对图片地址发送请求
        response = requests.get(url=img_src,headers=headers)
        img_date = response.content
        img_path='4kmm/'+img_name
        # print(img_path)
        with open(img_path,'wb') as fp:
            fp.write(img_date)
            print(img_name, '下载完成!')

问题:
1 .在个图片命名时出现乱码
解决方法:

  • 手动设定响应数据的格式 response.encoding=‘utf-8’
  • 通用处理乱码解决 img_name = img_name.encode(‘iso-8859-1’).decode(‘gbk’)
  1. xpath表达式一定要写正确
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页