1. 程式人生 > 實用技巧 >聚焦爬蟲:資料解析

聚焦爬蟲:資料解析

引子

回顧requests模組實現資料爬取的流程

  --指定url

  --發起請求

  --獲取響應資料

  --持久化儲存

其實,在上述流程中還需要較為重要的一步,就是在持久化儲存之前需要進行指定資料解析。因為大多數情況下的需求,我們都會指定去使用聚焦爬蟲,也就是爬取頁面中指定部分的資料值,

而不是整個頁面的資料。因此,本次課程中會給大家詳細介紹講解三種聚焦爬蟲中的資料解析方式。至此,我們的資料爬取的流程可以修改為:

  --指定url

  --發起請求

  --獲取響應資料

  --資料解析

  --持久化儲存

資料解析原理

 - 解析的區域性的文字內容都會在標籤之間或者標籤對應的屬性中進行儲存

1.進行指定標籤的定位
2.標籤或者標籤對應的屬性中儲存的資料值進行提取(解析)

如何實現資料解析

具體有三種方式:

  1.正則表示式

  2.bs4解析

  3.xpath解析

下面做逐一說明。

正則表示式解析

正則解析的原理就在從整個頁面的原始碼資料中,利用正則表示式,解析出區域性想要爬取的資料,然後進行持久化儲存。

import requests
import re
import os
if not os.path.exists('./qiutuLibs'):  # 如果沒有這個資料夾 建立這個資料夾
    os.makedirs('./qiutuLibs')
# UA偽裝 headers
= { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36' }
# 給出一個url模板 爬取第一頁到第三頁的圖片 url
= 'https://www.qiushibaike.com/imgrank/page/%d/' for i in (1,3): new_url = format(url%i) # 獲取整張頁面的資料 response = requests.get(url=new_url,headers=headers) page_info
= response.text # 匹配得到圖片的路徑 ex = r'<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>' # .* 貪婪匹配 .*? 惰性匹配
image_src = re.findall(ex, page_info, re.S) print(image_src) for src in image_src: fin_src = 'https:'+src fileName = fin_src.split('/')[-1] img_data = requests.get(url=fin_src).content with open('./qiutuLibs/%s'%fileName,'wb') as f: f.write(img_data) print(fin_src+'爬取完成')
ex = r'<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>'

"""
<div class="thumb">

<a href="/article/123202082" target="_blank">
<img src="//pic.qiushibaike.com/system/pictures/12320/123202082/medium/J90RGHEXAT6L11OZ.jpg" alt="糗事#123202082" class="illustration" width="100%" height="auto">
</a>
</div>
"""

bs4解析

環境安裝

- 需要將pip源設定為國內源,阿里源、豆瓣源、網易源等
   - windows
    (1)開啟檔案資源管理器(資料夾位址列中)
    (2)位址列上面輸入 %appdata%3)在這裡面新建一個資料夾  pip
    (4)在pip資料夾裡面新建一個檔案叫做  pip.ini ,內容寫如下即可
        [global]
        timeout = 6000
        index-url = https://mirrors.aliyun.com/pypi/simple/
        trusted-host = mirrors.aliyun.com
   - linux
    (1)cd ~2)mkdir ~/.pip
    (3)vi ~/.pip/pip.conf
    (4)編輯內容,和windows一模一樣
- 需要安裝:pip install bs4
     bs4在使用時候需要一個第三方庫,把這個庫也安裝一下
     pip install lxml

- 資料解析的原理:
  - 1.標籤定位
  - 2.提取標籤、標籤屬性中儲存的資料值


- bs4資料解析的原理:
  - 1.例項化一個BeautifulSoup物件,並且將頁面原始碼資料載入到該物件中
  - 2.通過呼叫BeautifulSoup物件中相關的屬性或者方法進行標籤定位和資料提取

基礎使用

使用流程:       
    - 導包:from bs4 import BeautifulSoup
    - 使用方式:可以將一個html文件,轉化為BeautifulSoup物件,然後通過物件的方法或者屬性去查詢指定的節點內容
        (1)轉化本地檔案:
             - soup = BeautifulSoup(open('本地檔案'), 'lxml')
        (2)轉化網路檔案:
             - soup = BeautifulSoup('字串型別或者位元組型別', 'lxml')
        (3)列印soup物件顯示內容為html檔案中的內容
基礎鞏固:
    (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選擇器返回永遠是列表,需要通過下標提取指定的物件

示例:爬取詩詞名句網關於三國演義的所有章節資訊

import requests
from bs4 import BeautifulSoup

if __name__=='__main__':
    url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36'
    }
    page_text = requests.get(url=url, headers=headers).text
    soup = BeautifulSoup(page_text,'lxml')  # 使用lxml編譯器
    title_list = soup.select('.book-mulu ul li a')  # 層級選擇標籤
    fileName = 'sanguo'
    f = open('%s.html'%fileName,'w',encoding='utf-8')
    for title in title_list:
        # 文章標題
        content_title = title.text
        # 詳情src
        src = title['href']  # 獲取href屬性
        # 完整src
        content_src = 'http://www.shicimingju.com' + src
        # 詳情內容
        detail_page = requests.get(url=content_src, headers=headers).text
        soup = BeautifulSoup(detail_page, 'lxml') # 將頁面文字物件加入解析器
        # 所有的文字資料
        detail_content = soup.find('div', class_='chapter_content').text # 獲取div標籤下所有的文字資料

        f.write(content_title+'\n'+detail_content)
        print(content_title+'爬取完成')

xpath解析(使用最多)

- xpath解析原理:

  - 1.例項化一個etree的物件,且需要將被解析的頁面原始碼資料載入到該物件中。

  - 2.呼叫etree物件中的xpath方法結合著xpath表示式實現標籤的定位和內容的捕獲。

常用的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物件例項化

如何例項化一個etree物件:from lxml import etree
- 1.將本地的html文件中的原始碼資料載入到etree物件中:
etree.parse(filePath)
- 2.可以將從網際網路上獲取的原始碼資料載入到該物件中
etree.HTML('page_text')
- xpath('xpath表示式')

示例:爬取58同城二手房的資訊

import requests
from lxml import etree
url = 'https://bj.58.com/ershoufang/'
header={
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36'
}

page_text = requests.get(url=url, headers=header).text  # 獲取網頁的所有資料
tree = etree.HTML(page_text)  # 生成etree物件
li_list = tree.xpath("//div[@class='content-side-left']/ul/li")  # 標籤定位
# xpath返回的是一個列表
f = open('58house.html','w',encoding='utf-8')
for li in li_list:
    house_title = li.xpath('./div[2]//a/text()')[0]
    house_price = li.xpath('./div[3]/p//text()')[0]  # 區域性查詢該起始元素用./表示
    house_meter_price = li.xpath('./div[3]/p//text()')[2]
    f.write('房型:'+house_title+'-------'+'價格:'+house_price+''+'   每平米:'+house_meter_price+'\n')
f.close()
print('爬取完成')