爬蟲之數據解析

来源:https://www.cnblogs.com/12345huangchun/archive/2019/03/03/10462719.html
-Advertisement-
Play Games

一、啥是數據解析 在上一篇關於爬蟲的博客里,我提到過,整個爬蟲分為四個部分,上一篇博客已經完成了前兩步,也就是我說的最難的地方,接下來這一步數據解析不是很難,但就是很煩人,但只要你有耐心,一步一步查找、排除就會提取出目標信息,這一步就相當於從接收到的龐大數據中提取出真正想要、有意義的信息,所以對於爬 ...


  一、啥是數據解析

  在上一篇關於爬蟲的博客里,我提到過,整個爬蟲分為四個部分,上一篇博客已經完成了前兩步,也就是我說的最難的地方,接下來這一步數據解析不是很難,但就是很煩人,但只要你有耐心,一步一步查找、排除就會提取出目標信息,這一步就相當於從接收到的龐大數據中提取出真正想要、有意義的信息,所以對於爬蟲來說,應該是很重要的。

  數據解析有三種方式,一是通過正則表達式,在python中就是利用re模塊;二是xpath;三是利用BeautifulSoup。

  二、正則表達式

  之前我們在學模塊的時候講過正則表達式,在這就不細說,獻上經常用到的

   單字元:
        . : 除換行以外所有字元
        [] :[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(正則表達式, 替換內容, 字元串)

  三、xpath

  1,常用表達式

屬性定位:
    #找到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

我們在使用xpath時,想要把字元串轉化為etree對象:
tree=etree.parse(文件名)#這種是把一個本地文件轉化成rtree對象
tree=etree.HTML(html標簽字元串)
tree.xpath(xpath表達式) #這樣就可以通過找到某個標簽,取出標簽的某個屬性就得到想要的結果

  2,示例一,爬取糗事百科圖片,保存在本地

import requests
from lxml import etree
#這是請求的路徑
url='https://www.qiushibaike.com/pic/' #這是偽造的瀏覽器UA
headers
={ 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36' }
#content拿到的是頁面代碼 content
=requests.get(url=url,headers=headers).text
#把這個頁面字元串代碼轉換成etree對象 tree
=etree.HTML(content)
#這是拿到所有class=‘thumb’的div標簽下的img標簽的src屬性,返回的是一個列表 img_src_list
=tree.xpath('//div[@class="thumb"]//img/@src')
#迴圈每個src,然後再去訪問,拿到圖片的位元組數據,存放於JPG文件,就得到每張圖片了
for img_src in img_src_list: c1=requests.get(url='https:'+img_src,headers=headers).content with open('%s.jpg'%img_src[:5],'wb') as f: f.write(c1)

  3,示例二,爬取煎蛋網的圖片

  這個就不是那麼簡單了,可以說是及其的難,我們用瀏覽器去訪問一下煎蛋網,查看一下每張圖片的src。

在這個元素的頁面上,也就是載入完畢後的HTML文件,上面可以看到img的src屬性,不用猜,這個肯定是圖片的地址,很是興奮,急急忙忙的寫程式,訪問頁面,拿去img的src值,然後再發起請求拿到圖片數據,保存下來,運行程式出錯了,不是預期的結果。在這,給大家分享一個反爬機制,對於圖片的src屬性並不是直接寫在html頁面上的,而是在載入頁面時用js得到img的src屬性,然後賦值過去,其實我們可以點開network,查看response,這個response才是真正返回的HTML文件內容,也就是接收的內容。如下圖:

  從response來看,它的所有圖片的src都是一樣的,說明並不是圖片真正的輸入窗路徑,後面跟了一個span標簽,class為img-hash,文本內容為一大段字元,可以猜出這是一個hash值,這個值就是img的src加密後的hash值,所以在載入頁面時,通過js把加密的字元解開就是img的src屬性,然後再賦給src(別問我是咋知道,我看別人這樣寫的,但確實是對的),這種通過js來動態載入的頁面是一種反爬機制,而且是一種讓人很頭疼的反爬機制。

  現在我們想要拿到他的src,就需要我們從返回的html文件中取出每個img-hash值,然後解密,得到真正的src,然後再對src發起請求。

import requests
from lxml import etree
headers={
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
}
import base64
url='http://jandan.net/ooxx'
content=requests.get(url=url,headers=headers).text
tree=etree.HTML(content)
hash_list=tree.xpath('//span[@class="img-hash"]/text()')   #這是拿到了所有的img-hsah值,存放在一個列表中

for i in hash_list:
    ur=base64.b64decode(i).decode()           #這裡用base64解密(不要問我為啥用這個解密,你咋知道的。大佬說,在js代碼發現有base64和md5的字樣,然而md5是不可逆的,所以就是base64了)
    con=requests.get(url='http:'+ur,headers=headers).content
    with open('%s.jpg'%i,'wb') as f:
        f.write(con)

  四、BeautifulSoup

  1,方法

from bs4 import BeautifulSoup
soup = BeautifulSoup(open('本地文件'), 'lxml')    #這是把一個本地文件轉換成BeautifulSoup對象
soup = BeautifulSoup('字元串類型或者位元組類型', 'lxml')#這是把HTML字元串轉換成BeautifulSoup對象

基礎鞏固:
    (1)根據標簽名查找
        - soup.a   只能找到第一個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")    #按類查找,得在把class寫成class_
        - 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)根據選擇器選擇指定的內容       #選擇器的規則和css一模一樣,
               select:soup.select('#feng')
        - 常見的選擇器:標簽選擇器(a)、類選擇器(.)、id選擇器(#)、層級選擇器
            - 層級選擇器:
                div .dudu #lala .meme .xixi  下麵好多級
                div > p > a > .lala          只能是下麵一級
        【註意】select選擇器返回永遠是列表,需要通過下標提取指定的對象

  2,實例一,爬取抽屜網的新聞標題和連接

from bs4 import BeautifulSoup
import requests
url='https://dig.chouti.com/'
headers={
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
}
con=requests.get(url=url,headers=headers).text
#這是實例化一個BeautifulSoup對象,對象就可以使用find、find_all等方法 soup
=BeautifulSoup(con,'lxml') a_list=soup.find_all('a',class_="show-content color-chag")#這是拿到了很多的a標簽, data_list=[] for a in a_list: dic={} dic['url']=a['href'] dic['content']=a.text.strip() data_list.append(dic) print(data_list)

  3,實例二,爬取58同城的房源信息

from bs4 import BeautifulSoup
import requests
import xlwt
import re
headers={
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
}
#這是創建一個Excel,並創建一個sheet表,設置屬性 workbook
= xlwt.Workbook(encoding='ascii') worksheet = workbook.add_sheet('My Worksheet') worksheet.col(0).width = 14000 worksheet.col(5).width = 24000 #發送請求 url='https://sz.58.com/ershoufang/?utm_source=market&spm=u-2d2yxv86y3v43nkddh1.BDPCPZ_BT&PGTID=0d30000c-0000-4591-0324-370565eccba8&ClickID=1' res=requests.get(url=url,headers=headers) con=res.text
#實例化一個對象 soup
=BeautifulSoup(con,'lxml') ss=soup.find('ul',class_='house-list-wrap') li_list=ss.find_all('li') #這是拿到了所有的li標簽 patter=re.compile(r'\s',re.S)
#這是迴圈每個li標簽,這裡拿到的每個li標簽還是一個BeautifulSoup對象,一樣擁有find、find_all等方法,對每個li標簽處理拿到每個房源的各種信息,然後寫入Excel中
for num in range(len(li_list)): worksheet.write(num, 0, label=li_list[num].find('a',tongji_label="listclick").text.strip()) p1=li_list[num].find_all('p')[0] span_list=p1.find_all('span') worksheet.write(num, 1, label=patter.sub('',span_list[0].text)) worksheet.write(num, 2, label=patter.sub('',span_list[1].text)) worksheet.write(num, 3, label=patter.sub('',span_list[2].text)) worksheet.write(num, 4, label=patter.sub('',span_list[3].text)) worksheet.write(num,5, label=patter.sub('',li_list[num].find('div',class_='jjrinfo').text)) worksheet.write(num, 6, label=li_list[num].find('p',class_='sum').text) worksheet.write(num, 7, label=li_list[num].find('p',class_='unit').text) workbook.save('myWorkbook.xls')

  4,實例三,爬取github

  github是需要登錄驗證的,所以我們照我上一篇講的模擬登錄的步驟,先用瀏覽器輸入一組錯誤信息,點擊登錄,找的登錄發送的路徑和數據結構,

  明顯發現這就是登錄請求的路徑,數據結構拿到了,再去拿到請求的路徑

  這下就可以發送請求,我最先訪問的是login頁面,得到cookie,帶這個cookie和data數據,往登錄的路徑發送請求,但不得行。於是乎回來看了一看,要求的數據結構,其中有個叫token的東西,怎麼那麼熟悉,這個不是那個隨機值CSRF-token,我就再去看了一下HTML頁面,

  確實是基於form表單發送請求的CSRF-token,這個東西是一個隨機值,所以我的程式得想去訪問login頁面,拿到登陸頁面,取得這個token值,放在data數據里,我之前程式的其他部分就不用變了,於是乎就成功了。

import requests
import re
url='https://github.com/login'

url1='https://github.com/session'
headers={
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36',
}
session=requests.session()
res1=session.get(url=url,headers=headers)
token=re.findall(r'name="authenticity_token".*?value="(?P<name>.*?)"',res1.text,re.S)[0]      #這就是用BeautifulSoup取得token值
data={
'commit': 'Sign in',
'utf8': '',
'authenticity_token': token,
'login': 'xxxxxx',
'password':'xxxxx'
}
session.post(url=url1,data=data,headers=headers)
url2='https://github.com/'
res=session.get(url=url2,headers=headers)
with open('github1.html','wb') as f:
    f.write(res.content)

   註意:

  1,xpath和BeautifulSoup都是針對標簽的解析方式,意思就是字元串得是一個標簽字元串,其次是要先找到標簽,然後獲取標簽的某個屬性值

  2,xpath和BeautifulSoup找的標簽,依然是一個對象,意思就是同樣可以用那些方法,就不用我們把找到的標簽再次實例化成對象


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 背景 公司為提高客服部門溝通效率對接電話呼叫中心,調研後選擇了亞馬遜的Amazon Connect服務,因為是國外業務沒有選擇用阿裡雲,怕有坑。 Amazon Connect後臺 需要在後臺創建“聯繫流”,也就是用戶接通電話後我們提供的一系列功能選項,比如開始放一段歡迎語音,然後提示用戶選擇1,2, ...
  • 今天我們來詳解一下git的各種命令,此為git的第一篇,後續還會有好幾篇,希望大家看了能有所進步 Git Commit Git 倉庫中的提交記錄保存的是你的目錄下所有文件的快照,就像是把整個目錄複製,然後再粘貼一樣,但比複製粘貼優雅許多! Git 希望提交記錄儘可能地輕量,因此在你每次進行提交時,它 ...
  • 在JavaScript中,使用var創建變數,會創建全局變數或局部變數。 只有在非函數內創建的變數,才是全局變數,該變數可以在任何地方被讀取。 而在函數內創建變數時,只有在函數內部才可讀取。在函數外部時,調用函數也無法讀取局部變數。 function test(){ var g = 5; } // ...
  • 計算屬性 1.1 什麼是計算屬性: 插值表達式常用於簡單的運算,當其過長或邏輯複雜時,會難以維護,這時應該使用計算屬性。 插值表達式里的值是JS表達式 所有的計算屬性都以函數的形式寫在Vue實例內的computed選項內,最終返回計算後的結果。 1.2 計算屬性的用法 在一個計算屬性里可以完成各種復 ...
  • MVC設計模式:modle層,view層,controller層 以前學習的servlet其實就是一個java類,或者說經過規範的java類,實際進行跳轉時,還是要在web.xml文件中配置才能正常跳轉。 controller層可以放servlet,在SpringMVC中則可以創建java類通過@c ...
  • 1.hello 1.hello 1.hello 1.hello 消息生產者p將消息放入隊列 消費者監聽隊列,如果隊列中有消息,就消費掉,消息被拿走後,自動從隊列刪除(隱患,消息可能沒有被消費者正確處理,已經消失了,無法恢復) 應用場景:聊天室 案例: 1>.首先準備依賴 <dependency> < ...
  • 環境配置 部署環境 部署環境:windows server 2008 r2 enterprise 官方安裝部署文檔:http://www.rabbitmq.com/install-windows.html官方文檔說明 下載erlang 原因在於RabbitMQ服務端代碼是使用併發式語言erlang編 ...
  • 究竟啥才是互聯網架構“高併發” 一、什麼是高併發 高併發(High Concurrency)是互聯網分散式系統架構設計中必須考慮的因素之一,它通常是指,通過設計保證系統能夠同時並行處理很多請求。 高併發相關常用的一些指標有響應時間(Response Time),吞吐量(Throughput),每秒查 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...