• 爬虫的四种数据解析方式


    一, 引入

    回顾requests实现数据爬取的流程:

    1. 指定url
    2. 基于requests模块发起请求
    3. 获取响应对象中的数据
    4. 进行持久化存储

    其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指定数据解析。因为大多数情况下的需求,我们都会指定去使用聚焦爬虫,也就是爬取页面中指定部分的数据值,而不是整个页面的数据。数据爬取的流程可以修改为:

    1. 指定url
    2. 基于requests模块发起请求
    3. 获取响应中的数据
    4. 数据解析
    5. 进行持久化存储

    实现方式:

    • 正则
    • bs4
    • xpath
    • pyquery

    数据解析的通用原理是什么?

    • 标签的定位
    • 数据的提取

    页面中的相关的字符串的数据都存储在哪里呢?

    • 标签中间
    • 标签的属性中

    二, 正则解析

    常用正则表达式回顾:

    单字符:
        . : 除换行以外所有字符
        [] :[aoe] [a-w] 匹配集合中任意一个字符
        d :数字  [0-9]
        D : 非数字
        w :数字、字母、下划线、中文
        W : 非w
        s :所有的空白字符包,括空格、制表符、换页符等等。等价于 [ f
    
    	v]。
        S : 非空白
    数量修饰:
        * : 任意多次  >=0
        + : 至少1次   >=1
        ? : 可有可无  0次或者1次
        {m} :固定m次 hello{3,}
        {m,} :至少m次
        {m,n} :m-n次
    边界:
        $ : 以某某结尾 
        ^ : 以某某开头
    分组:
    	(ab)  
    贪婪模式: .*
    非贪婪(惰性)模式: .*?
    
    re.I : 忽略大小写
    re.M :多行匹配
    re.S :单行匹配
    
    re.sub(正则表达式, 替换内容, 字符串)
    

    练习:

    将煎蛋网中的图片数据进行爬取且存储在本地

    import requests
    import re
    import os
    from urllib import request
    file_path = './煎蛋网/'
    if not os.path.exists(file_path):
        os.mkdir(file_path)
    url = 'http://jandan.net/pic/MjAxOTEwMDktNjY=#comments'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36'
    }
    page_text = requests.get(url, headers=headers).text
    ex = '<div class="text">.*?<img src="(.*?)" referrerPolicy.*?</div>'
    src_list = re.findall(ex, page_text, re.S)
    for src in src_list:
        if 'org_src' in src:
            src = re.findall('org_src="(.*?)" onload', src)[0]
        img_url = 'http:' + src
        img_path = file_path + src.split('/')[-1]
        request.urlretrieve(img_url, img_path)
        print(src.split('/')[-1], '爬取成功~~')
    

    三, Xpath解析

    • 环境的安装
      • pip install lxml
    • 解析原理
      • 实例化一个etree的对象,且把即将被解析的页面源码数据加载到该对象中
      • 调用etree对象中的xpath方法结合着不同形式的xpath表达式进行标签定位和数据提取
    • etree对象的实例化
      • etree.parse('fileName')
      • etree.HTML(page_text)
    • 标签定位
      • 最左侧的/:一定要从根标签开始进行标签定位
      • 非最左侧的/:表示一个层级
      • 最左侧的//:可以从任意位置进行指定标签的定位
      • 非最左侧的//:表示多个层级
      • 属性定位://tagName[@attrName="value"]
      • 索引定位://tagName[@attrName="value"]/li[2],索引是从1开始
      • 逻辑运算:
        • 找到href属性值为空且class属性值为du的a标签
        • //a[@href="" and @class="du"]
      • 模糊匹配:
        • //div[contains(@class, "ng")]
        • //div[starts-with(@class, "ta")]
    • 取文本
      • /text():直系的文本内容
      • //text():所有的文本内容
    • 取属性
      • /@attrName

    练习:

    需求:爬取虎牙主播名称,热度和标题

    from lxml import etree
    url = 'https://www.huya.com/g/xingxiu'
    page_text = requests.get(url, headers=headers).text
    tree = etree.HTML(page_text)
    li_list = tree.xpath('//ul[@id="js-live-list"]/li')
    for li in li_list:
        title = li.xpath('./a[2]/text()')[0]
        avatar = li.xpath('./span/span[1]/i/text()')[0]
        hot = li.xpath('./span/span[2]/i[2]/text()')[0]
        print(title, avatar, hot)
    

    爬取http://pic.netbian.com/4kmeinv/中前五页的图片数据

    • 中文乱码的处理
    • 多页码数据的爬取
    file_path = './妹子图/'
    if not os.path.exists(file_path):
        os.mkdir(file_path)
    url = 'http://pic.netbian.com/4kmeinv/index_{}.html'
    for page in range(1, 6):
        if page == 1:
            new_url = 'http://pic.netbian.com/4kmeinv/'
        else:
            new_url = url.format(page)
        page_text = requests.get(new_url, headers=headers).text
        tree = etree.HTML(page_text)
        li_list = tree.xpath('//div[@class="slist"]/ul/li')
        for li in li_list:
            title = li.xpath('./a/b/text()')[0].encode('iso-8859-1').decode('gbk')
            src = 'http://pic.netbian.com' + li.xpath('./a/img/@src')[0]
            img_path = file_path + title + '.' + src.split('.')[-1]
            request.urlretrieve(src, img_path)
        print('第{}页爬取完毕'.format(page))
    

    爬取全国城市的名称

    url = 'https://www.aqistudy.cn/historydata/'
    page_text = requests.get(url, headers=headers).text
    # soup = BeautifulSoup(page_text, 'lxml')
    # hot_cities = soup.select('.hot li a')
    # other_cities = soup.select('.all li a')
    # cities = hot_cities + other_cities
    # for city in cities:
    #     print(city.text)
    
    tree = etree.HTML(page_text)
    # | 表示 or
    cities = tree.xpath('//div[@class="hot"]//a/text() | //div[@class="all"]//a/text()')
    for city in cities:
        print(city)
    

    四, BeautifulSoup解析

    • 环境的安装:
      • pip install bs4
      • pip install lxml
    • bs4的解析原理:
      • 实例化一个BeautifulSoup的一个对象,把即将被解析的页面源码数据加载到该对象中
      • 需要调用BeautifulSoup对象中的相关的方法和属性进行标签定位和数据的提取
    • BeautifulSoup的实例化
      • BeautifulSoup(fp,'lxml'):将本地存储的html文档中的页面源码数据加载到该对象中
      • BeautifulSoup(page_text,'lxml'):将从互联网中请求到的页面源码数据加载到该对象中
    • 标签的定位
      • soup.tagName:只可以定位到第一个tagName标签
      • 属性定位:soup.find('tagName',attrName='value'),只可以定位到符合要求的第一个标签
        • 特别的: class属性 class_='value'
        • findAll:返回值是一个列表。可以定位到符合要求的所有标签
      • 选择器定位:soup.select('选择器')
        • 选择器:id,class,tag,层级选择器(大于号表示一个层级,空格表示多个层级)
    • 取文本
      • text:将标签中所有的文本取出
      • string:将标签中直系的文本取出
    • 取属性
      • tag['attrName']

    练习:

    需求:使用bs4解析红楼梦小说的标题和内容,存储到本地

    url = 'http://www.shicimingju.com/book/hongloumeng.html'
    page_text = requests.get(url, headers=headers).text
    soup = BeautifulSoup(page_text, 'lxml')
    a_list = soup.select('.book-mulu a')
    f1 = open('红楼梦.text', 'w', encoding='utf-8')
    for a in a_list:
        title = a.text
        book_url = 'http://www.shicimingju.com' + a['href']
        book_text = requests.get(book_url, headers=headers).text
        book_soup = BeautifulSoup(book_text, 'lxml')
        book_data = book_soup.select('.chapter_content')[0].text
        f1.write(title + '
    ' + book_data + '
    ')
        print(title, '爬取成功~')
    f1.close()
    

    五, pyquery解析

    和jQuery高度相似,容易上手,但是效率和正确率不太好.

    https://blog.csdn.net/sunt2018/article/details/85932516

  • 相关阅读:
    TCP服务器是否需要心跳包?
    用最简单的函数实现功能:判断一个int数据是否是2的x次幂(不能使用循环)。
    防止程序启动两次的方法CreateMutex()
    WINDOWS操作系统中可以允许最大的线程数
    setsockopt 设置socket 详细用法
    我的结论:DX9不支持非2的次幂尺寸纹理,还得显卡说了算
    D3DX_DEFAULT_NONPOW2
    【解决】Select网络模型问题——奇怪的发送接收问题
    CRC32 简单使用
    .NET开发总结 2010年2月
  • 原文地址:https://www.cnblogs.com/maqian/p/12359315.html
Copyright © 2020-2023  润新知