爬蟲之四種數據解析方式


一, 引入

回顧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\n\r\t\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 + '\n' + book_data + '\n')
    print(title, '爬取成功~')
f1.close()

五, pyquery解析

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM