Python爬虫从入门到进阶(二)— 数据解析

一、基础知识

1、常见的数据解析方式:

  • 正则:既可以在python中使用,也可以在其他语言中使用;

  • bs4:只可以在python语言中使用;

    • 实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中;

    • 通过调用BeautifulSoup对象中的相关属性或者方法进行标签定位和数据提取;

      需要安装两个三方模块:

    • pip install bs4 (BeautifulSoup对象存在于bs4这个模块中)

    • pip install lxml (解析器)    

  • xpath(重点):通用性最强;

2、数据解析的原理:

  • 聚焦爬虫解析的局部文本内容,都会在标签之间或者标签对应的属性中进行存储;

  • 进行指定标签的定位;

  • 标签或标签对应的属性值中存取的数据值进行提取(解析);

3、聚焦爬虫相对于通用爬虫的编码流程会多增加一条:

  • 指定url

  • 发起请求

  • 获取响应数据

  • 数据解析

  • 持久化存储

4、xpath解析:最常用且最便捷高效得一种解析方式,通用性也好:

  • xpath解析原理:

    • 实例化一个etree对象,需要将被解析得页面源码数据加载到该对象中;

    • 调用etree对象中得xpath方法,结合xpath表达式实现表得定位+内容得捕获;

  • 环境的安装:

    • pip install lxml

  • 如何实例化一个etree对象:

    • 将本地的html文档中的源码数据加载到etree对象中:etree.parse(filePath)

    • 将互联网上获取到的源码数据加载到etree对象中:etree.HTML(page_text)

    • 使用的时候:et.xpath('xpath表达式')

  • xpath表达式:

    • /:标识从根节点开始定位,且单/表示一个层级;

    • //:表示多个层级,可以表示从任意位置开始定位;

    • 属性定位:tag[@attrName='attrValue'],例如://div[@class='song'];

    • 索引定位:例如://div[@class='song']/p[3],注意:这里的索引是从1开始的;

    • 获取文本内容:

        • /text() :获取的是标签中直系的文本内容,返回值为数组,我们一般取索引为[0]位置的值;

        • //text() :获取的是标签中所有的文本内容,包括非直系的,返回值为数组;

    • 获取属性值:

        • /@attrName :  获取某个标签的属性值,例如://div[@class='song']/img/@src;

  • xpath补充:xpath表达式可以使用 | 或连接符进行拼接:

all_list = tree.xpath('//div[@class="bottom"]/ul/li/a | //div[@class="bottom"]/ul/div[2]/li/a')

# 通过这样的可拼接特性,xpath表达式就变得更加的强大!


二、实战小功能案例 — 58同城二手车图片(正则解析)

1、打开网站进行分析:https://sh.58.com/ershouche/

image.png

我们可以得到如下结论:

2、有了上面的核心分析结论后,我们就直接开始coding编码吧:

import requests
import re
import os

if __name__ == '__main__':
    # 先准备一个文件夹,保存所有的图片
    if not os.path.exists('./output/58pics'):
        os.mkdir('./output/58pics')

    # 准备UA伪装
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36'
    }
    # 设置一个通配的url模板字符串
    temp_url = 'https://sh.58.com/ershouche/pn%d/'
    # 提前分析定义好正则表达式(使用.*?进行通配,\进行转义,(.*?)中的内容将是我们最终获得到的内容)
    ex = '<div class="info--pics">.*?data-original="(.*?)\?.*?</div>'

    # 正式干活,虽然页面显示有70页,但是我们只测试个5页即可
    for pageNum in range(1, 6):
        real_url = temp_url % pageNum
        response_text = requests.get(real_url, headers=headers).text
        img_url_list = re.findall(ex, response_text, re.S)
        print(img_url_list, "图片列表...")

        # 下载img_url对应的图片到本地
        for img_url in img_url_list:
            # 取/分割的最后一段为图片名称,确保不重复
            img_name = str(img_url).split("/")[-1]
            # 发起请求,获得的数据为二进制数据,所以得用.content获取
            img_data = requests.get(img_url, headers=headers).content
            # 将img_data数据存储到文件,注意mode为‘wb’,因为存储的是二进制数据,且不需要指定encoding
            with open("./output/58pics/" + img_name, 'wb') as fp:
                fp.write(img_data)
            print(img_name, "下载成功...")

3、我们运行程序进行测试:

image.png

查看最终下载到的图片:

image.png

非常Nice! (#^.^#)


三、实战小功能案例 — 爬取《三国演义》所有章节标题和内容(bs4解析)

1、安装bs4、lxml模块:

# 如果报错的话,检查是不是开着vpn
pip install bs4
pip install lxml

2、浏览器访问网站:https://www.shicimingju.com/book/sanguoyanyi.html

image.png

爬取思路:

  • 首先访问首页,可以轻松获得所有的章节标题:https://www.shicimingju.com/book/sanguoyanyi.html

  • 每一个章节都能拼接出每一章节详情页的url:https://www.shicimingju.com/book/sanguoyanyi/1.html

  • 再从每一个详情页中解析出正文内容;

  • 页面标签的层级关系,class = 'book-mulu' 的div标签 > ul >li > a标签

3、直接开始coding编码:

import requests
from bs4 import BeautifulSoup
import os

if __name__ == '__main__':
    if not os.path.exists('./output/sanguo'):
        os.mkdir('./output/sanguo')

    # 准备UA伪装
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36'
    }

    # 设置url模板
    index_url = 'https://www.shicimingju.com/book/sanguoyanyi.html'
    detail_base_url = 'https://www.shicimingju.com'

    # 开始干活
    # 1、获取首页源码
    index_response = requests.get(index_url, headers=headers)
    index_response.encoding = 'utf-8'
    index_text = index_response.text
    # 实例化BeautifulSoup对象
    index_soup = BeautifulSoup(index_text, 'lxml')
    # 解析出章节标题和详情页的url
    li_list = index_soup.select('.book-mulu > ul > li')

    # 2、提前准备好一个文件,这样每一次直接追加即可:
    fp = open('./output/sanguo/三国演义.txt', 'w', encoding='utf-8')

    # 3、处理首页的soup元素,并发起详情页的请求
    for li in li_list:
        # 直接a.string获取a标签中的文本作为title
        title = li.a.string
        detail_url = detail_base_url + li.a['href']
        # 对详情页发起请求,并解析出章节内容
        detail_response = requests.get(detail_url, headers=headers)
        detail_response.encoding = 'utf-8'
        detail_text = detail_response.text
        detail_soup = BeautifulSoup(detail_text, 'lxml')
        content_tag = detail_soup.find('div', class_='chapter_content')

        # 将title和正文全部写入到提前准备好的fp
        fp.write(title + ':\n' + content_tag.text + '\n')
        print(title, ':章节下载完成')

4、运行程序,测试结果:

image.png

查看《三国演义.txt》文本文件:

image.png

非常Nice,没毛病,老铁!o(* ̄︶ ̄*)o


四、实战小功能案例 — 4K图片解析下载(解决编码乱码用例)(xpath解析)

1、打开网址对页面结构进行分析:https://pic.netbian.com/4kmeinv/

image.png

  • 所有的图片都被包裹在 //ul[class=clearfix] -> li -> a -> img标签中;

  • src属性中是图片的url链接,alt中是图片的名称;

2、话不多说,直接coding编码:

import requests
from lxml import etree
import os

if __name__ == '__main__':
    if not os.path.exists('./output/4kpics'):
        os.mkdir('./output/4kpics')

    # 准备UA伪装
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36'
    }

    url = 'https://pic.netbian.com/4kmeinv/'
    base_url = 'https://pic.netbian.com/'

    # 开始干活
    response = requests.get(url, headers=headers)
    resp_text = response.text
    # 获得etree对象
    et = etree.HTML(resp_text)
    li_list = et.xpath('//ul[@class="clearfix"]/li')
    for li in li_list:
        img_url = li.xpath('./a/img/@src')[0]
        img_name = li.xpath('./a/img/@alt')[0]
        # 由于纯在乱码的问题,我们可以使用一个很常用的方式进行重新编码解码
        new_img_name = img_name.encode('iso-8859-1').decode('gbk')
        img_data = requests.get(base_url+img_url, headers=headers).content
        with open('./output/4kpics/'+new_img_name+'.jpg', 'wb') as fp:
            fp.write(img_data)
        print(new_img_name, "下载完成....")

3、测试,查看结果:

image.png

看下载好的图片:

image.png

Very Nice! (●'◡'●)

jiguiquan@163.com

文章作者信息...

留下你的评论

*评论支持代码高亮<pre class="prettyprint linenums">代码</pre>

相关推荐