• Python:数据解析(bs4 / xpath)


    最近在看B站上的视频学习资料,此文是关于用bs4/xpath做数据解析相关的一些使用实例。

    bs4解析

    • 环境的安装:
      • pip install bs4
      • pip install lxml
    • bs4数据解析的解析原理/流程
      • 实例化一个BeautifulSoup对象,且将等待解析的数据加载到该对象中
        • 方式1: BeautifulSoup(f,'lxml'):解析本地存储的html文件
        • 方式2: BeautifulSoup(page_text,'lxml'):解析互联网上请求到的页面数据
      • 调用BeautifulSoup对象中的相关方法和属性进行标签定位和数据的提取
    • 标签定位
      • soup.tagName: 返回第一次出现的tagName标签
      • 属性定位:soup.find('tagName',attrName='value')
      • findAll和find的用法一样,但是返回值不一样,findAll返回列表
      • 选择器定位:select('selector')
    • 数据提取
      • 提取标签中存在的数据
        • .string: 取出标签直系的文本内容
        • .text: 取出标签中所有的文本内容
      • 提取标签属性中存储的数据
        • tagName['attrName']
    import requests
    from bs4 import BeautifulSoup
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'
    }
    f = open('./test.html','r')
    soup = BeautifulSoup(f,'lxml')
    soup.div # 标签定位
    soup.find('div',class_='song') # 属性定位:根据树新定位具体的标签,class属性为song的div标签,因为class是内置属性,所以要加下划线class_,如果是id则直接用id='xxx'
    soup.finAll('a',id='feng')
    soup.select('#feng') # 根据id选择器定位a标签
    soup.select('.song') # 定位class为song的标签
    #层级选择器
    soup.select('.tang > ul > li > a') # >表示一个层级
    soup.select('.tang a') # 空格表示多个层级
    
    soup.p.string # 取出p标签直系的文本内容
    soup.div.text # 取出div标签中所有的文本内容
    soup.a['href'] # 取出按标签属性为href的数据
    # 使用bs4解析爬取三国演义整篇小说内容:http://www.shicimingju.com/book/sanguoyanyi.html
    
    # 从首页解析出章节的标题和详情页的url
    url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
    page_text = requests.get(url, headers=headers).text # 首页页面的源码数据
    f = open('./sanguoyanyi.txt','w',encoding='utf-8')
    # 数据解析(章节标题,详情页的url)
    soup = BeautifulSoup(page_text,'lxml')
    a_list = soup.select('.book-mulu > ul > li > a')
    for a in a_list:
        title = a.string
        url_detail = 'http://www.shicimingju.com' + a['href']
        # 解析提取章节内容
        page_text_detail = requests.get(url_detail, headers=headers).text
        # 解析详情页中的章节内容
        soup = BeautifulSoup(page_text_detail,'lxml')
        content = soup.find('div',class_='chapter_content').text
    
        f.write(title + ':' + content + '
    ')
        print(title,'下载成功')

    xpath解析

    • xpath解析原理
      • 实例化一个etree对象,且将即将被解析的数据加载到该对象中
        • 解析本地存储的html文档:etree.parse('fileName')
        • 解析网上爬取的html数据:etree.HTML('page_text')
      • 使用etree对象中的xpath方法结合着不同的xpath表达式实现标签定位和数据提取
    • 标签定位
      • 最左侧的/: 必须要从跟标签开始逐层的定位目标标签
      • 非最左侧的/: 表示一个层级
      • 最左侧的//: 可以从任意位置定义目标标签
      • 非最左侧的//: 表示多个层级
      • 属性定位: //tagName[@atrrName='value']
      • 索引定位: //tagName[index],index是从1开始的,不是从0
      • 模糊匹配:
        • //div[contains(@class,'ng')] 定位到class属性中包含ng的div标签
        • //div[starts-with(@class,'ta')] 定位到class属性值中以ta开头的div标签
    • 数据提取
      • 取标签中的数据
        • /text(): 直系文本内容
        • //text(): 所有文本内容
      • 取属性的数据
        • tagName/@attrName
    from lxml import etree
    import os
    tree = etree.parse('./test.html')
    tree.xpath('/html/head') # 从根标签开始定位head标签,返回<Element>列表
    tree.xpath('//head') # 将html文档中所有的head标签定位到
    tree.xpath('//div[@class="song"]') # 定位class为song的div标签
    tree.xpath('//li[1]') #定位第一个li标签
    tree.xpath('//a[@id="feng"]/text()')  # 取出id为feng的a标签的直系内容
    tree.xpath('//div[@class="song"]//text()') # 取出class为song的div标签里面的所有内容
    tree.xpath('//a[@id="feng"]/@href') # 取出id为feng的a标签中属性为href的值
    
    # 爬取图片数据和图片名称,并保存到本地
    # 第一页:http://pic.netbian.com/4kmeinv/
    # 非第一页:http://pic.netbian.com/4kmeinv/index_2.html
    dir_name = 'imgLibs'
    if not os.path.exists(dir_name):
        os.mkdir(dir_name)
    
    url = 'http://pic.netbian.com/4kmeinv/index_%d.html'
    for page in range(1,6):
        if page == 1:
            new_url = 'http://pic.netbian.com/4kmeinv/'
        else:
            new_url = format(url%page) # 表示非第一页的url
        response = requests.get(new_url, headers=headers)
        response.encoding = 'gbk'
        page_text = response.text
        tree = etree.HTML(page_text) # 解析图片地址和图片名称
        li_list = tree.xpath('//div[@class="slist"]/ul/li') # 全局解析
        for li in li_list:
            img_src = 'http://pic.netbian.com' + li.xpath('./a/img/@src')[0] # 局部解析,./表示xpath对调用者对应的标签
            img_name = li.xpath('./a/img/@alt')[0] + '.jpg'
            img_data = requests.get(img_src,headers=headers).content
    #         print(img_src, img_name)
            file_path = dir_name + '/' + img_name
            with open(file_path,'wb') as f:
                f.write(img_data)
            print(img_name,'下载成功')
    
    
    # 如何提升xpath表达式的通用性
    url = 'https://www.aqistudy.cn/historydata/'
    page_text = requests.get(url,headers=headers).text
    tree = etree.HTML(page_text)
    hot_cities = tree.xpath('//div[@class="bottom"]/ul/li/a/text()')
    all_cities = tree.xpath('//div[@class="bottom"]/ul/div[2]/li/a/text()')
    # 上述2个xpath表达式可以合并成以下一个xpath表达式
    cities = tree.xpath('//div[@class="bottom"]/ul/li/a/text() | //div[@class="bottom"]/ul/div[2]/li/a/text()')
    print(cities)
    • 想要解析出一张页面中指定的局部带标签的数据
      • bs4, 使用bs4定位标签后,直接返回的就是标签内容

    参考:(P7~P8)

  • 相关阅读:
    JavaScript函数柯里化的一些思考
    Javascript Promise 学习笔记
    ArcGIS加载高德、OSM和谷歌等地图
    抓取“矢量”的实时交通流量数据
    uniapp使用swiper组件做tab切换动态获取高度
    elementui中弹出框不能自动换行的解决方案
    前端面试题总结
    关于nodejs中的增删改查
    关于cookie与本地 存储的区别的问题。
    微信小程序实现如丝顺滑可移动悬浮按钮(超简单)
  • 原文地址:https://www.cnblogs.com/danvy/p/12740508.html
Copyright © 2020-2023  润新知