1. 程式人生 > 實用技巧 >爬蟲2 資料解析 --圖片

爬蟲2 資料解析 --圖片

### 回顧

- requests作用:模擬瀏覽器發起請求

- urllib:requests的前身

- requests模組的編碼流程:

- 指定url

- 發起請求:

- get(url,params,headers)

- post(url,data,headers)

- 獲取響應資料

- 持久化儲存

- 引數動態化:

- 有些情況下我們是需要將請求引數進行更改。將get或者post請求對應的請求引數封裝到一個字典(鍵值對==請求引數)中,然後將改字典作用到get方法的params引數中或者作用到psot方法的data引數中

- UA檢測(反爬機制):

- 什麼是UA:請求載體的身份標識。伺服器端會檢測請求的UA來鑑定其身份。

- 反反爬策略:UA偽裝。通過抓包工具捕獲某一款瀏覽器的UA值,封裝到字典中,且將該字典作用到headers引數中

- 動態載入的資料

- 通過另一個單獨的請求請求到的資料

- 如果我們要對一個陌生的網站進行指定資料的爬取?

- 首先要確定爬取的資料在改網站中是否為動態載入的

- 是:通過抓包工具實現全域性搜尋,定位動態載入資料對應的資料包,從資料包中提取請求的url和請求引數。

- 不是:就可以直接將瀏覽器位址列中的網址作為我們requests請求的url

### 今日內容

- 資料解析

- 資料解析的作用:

- 可以幫助我們實現聚焦爬蟲

- 資料解析的實現方式:

- 正則

- bs4

- xpath

- pyquery

- 資料解析的通用原理

- 問題1:聚焦爬蟲爬取的資料是儲存在哪裡的?

- 都被儲存在了相關的標籤之中and相關標籤的屬性中

- 1.定位標籤

- 2.取文字或者取屬性

如何爬取圖片呢?

import requests
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36
' } #如何爬取圖片 url = 'https://pic.qiushibaike.com/system/pictures/12223/122231866/medium/IZ3H2HQN8W52V135.jpg' img_data = requests.get(url,headers=headers).content #byte型別資料 with open('./img.jpg','wb') as fp: fp.write(img_data)
爬取圖片

2、引用 urllib(建議不用,因為不能UA偽裝)

#弊端:不能使用UA偽裝
from urllib import request
url = 'https://pic.qiushibaike.com/system/pictures/12223/122231866/medium/IZ3H2HQN8W52V135.jpg'
request.urlretrieve(url,filename='./qiutu.jpg')
urllib

到糗事百科 爬取圖片

import re
import os

#1.使用通用爬蟲將前3頁對應的頁面原始碼資料進行爬取
#通用的url模板(不可變)
dirName = './imgLibs'
if not os.path.exists(dirName):
    os.mkdir(dirName)
url = 'https://www.qiushibaike.com/pic/page/%d/'
for page in range(1,4):
    new_url = format(url%page)
    page_text = requests.get(new_url,headers=headers).text #每一個頁碼對應的頁面原始碼資料
    #在通用爬蟲的基礎上實現聚焦爬蟲(每一個頁碼對應頁面原始碼資料中解析出圖片地址)
    ex = '<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
    img_src_list = re.findall(ex,page_text,re.S)
    for src in img_src_list:
        src = 'https:'+src
        img_name = src.split('/')[-1]
        img_path = dirName+'/'+img_name #./imgLibs/xxxx.jpg
        request.urlretrieve(src,filename=img_path)
        print(img_name,'下載成功!!!')
#糗圖爬取1-3頁所有的圖片

- bs4解析

- bs4解析的原理:

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

- 呼叫BeautifulSoup物件中的相關方法和屬性進行標籤定位和資料提取

- 環境的安裝:

- pip install bs4

- pip install lxml

- BeautifulSoup的例項化:

- BeautifulSoup(fp,'lxml'):將本地儲存的一個html文件中的資料載入到例項化好的BeautifulSoup物件中

- BeautifulSoup(page_text,'lxml'):將從互聯網上獲取的頁面原始碼資料載入到例項化好的BeautifulSoup物件中

- 定位標籤的操作:

- soup.tagName:定位到第一個出現的tagName標籤             soup.div

- 屬性定位:soup.find('tagName',attrName='value')              soup.find('div',class_='c1')    

- 屬性定位:soup.find_all('tagName',attrName='value'),返回值為列表:       soup.find_all('div',id='d1')

- 選擇器定位:soup.select('選擇器')                     soup.select('#feng') 

- 層級選擇器:>表示一個層級 空格表示多個層級              soup.select('.tang > ul > li')

- 取文字

- .string:獲取直系的文字內容

- .text:獲取所有的文字內容

- 取屬性

- tagName['attrName']

from bs4 import BeautifulSoup
fp = open('./test.html','r',encoding='utf-8')

soup = BeautifulSoup(fp,'lxml')      # 本地檔案控制代碼
soup.div
soup.find('div',class_='song')
soup.find('a',id="feng")
soup.find_all('div',class_="song")
soup.select('#feng')
soup.select('.tang > ul > li')    # >表示一層級(直系)
soup.select('.tang li')             # 空格表示多個層級(孫子輩)
a_tag = soup.select('#feng')[0]
a_tag.text
div = soup.div
div.string       # 獲取直系文字
div = soup.find('div',class_="song")
div.string    # 所有文字
a_tag = soup.select('#feng')[0]
a_tag['href']        

Ok 來下載小說吧

fp = open('sanguo.txt','w',encoding='utf-8')
main_url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
page_text = requests.get(main_url,headers=headers).text
#解析出章節名稱和章節詳情頁的url
soup = BeautifulSoup(page_text,'lxml')
a_list = soup.select('.book-mulu > ul > li > a') #返回的列表中儲存的是一個個a標籤
for a in a_list:
    title = a.string
    detail_url = 'http://www.shicimingju.com'+a['href']
    detail_page_text = requests.get(detail_url,headers=headers).text
    #解析詳情頁中的章節內容
    soup = BeautifulSoup(detail_page_text,'lxml')
    content = soup.find('div',class_='chapter_content').text
    fp.write(title+':'+content+'\n')
    print(title,'下載成功!')
fp.close()
爬取三國整篇內容(章節名稱+章節內容)

  • xpath表示式:xpath方法的返回值一定是一個列表
    • 最左側的/表示:xpath表示式一定要從根標籤逐層進行標籤查詢和定位
    • 最左側的//表示:xpath表示式可以從任意位置定位標籤
    • 非最左側的/:表示一個層級
    • 非最左側的//:表示誇多個層級
    • 屬性定位://tagName[@attrName="value"]    //div[@class='c1']
    • 索引定位://tagName[index] 索引是從1開始   //li[1]
  • 取文字:
    • /text():直系文字內容
    • //text():所有的文字內容
  • 取屬性:
    • /@attrName @ href
      from lxml import etree
      tree = etree.parse('./test.html')
      tree.xpath('/html/head/title')
      tree.xpath('//title')
      tree.xpath('/html/body//p')
      tree.xpath('//p')
      tree.xpath('//div[@class="song"]')
      tree.xpath('//li[7]')
      tree.xpath('//a[@id="feng"]/text()')[0]
      tree.xpath('//div[@class="song"]//text()')
      tree.xpath('//a[@id="feng"]/@href')
      from lxml import etree
      url = 'https://www.qiushibaike.com/text/'
      page_text = requests.get(url,headers=headers).text
      
      #解析內容
      tree = etree.HTML(page_text)
      div_list = tree.xpath('//div[@id="content-left"]/div')
      for div in div_list:
          author = div.xpath('./div[1]/a[2]/h2/text()')[0]#實現區域性解析
          content = div.xpath('./a[1]/div/span//text()')
          content = ''.join(content)
          
          print(author,content)
      #爬取糗百中的段子內容和作者名稱

    • 有時候爬取的資料出現亂碼 可以參考下面:
      •   img_name = img_name.encode('iso-8859-1').decode('gbk')
        •   先用iso-8859-1 來編碼 再用gbk 解碼 即可
    • import os
      dirName = './meinvLibs'
      if not os.path.exists(dirName):
          os.mkdir(dirName)
      url = 'http://pic.netbian.com/4kmeinv/index_%d.html'
      for page in range(1,11):
          if page == 1:
              new_url = 'http://pic.netbian.com/4kmeinv/' 
          else:
              new_url = format(url%page)
          page_text = requests.get(new_url,headers=headers).text
          tree = etree.HTML(page_text)
          a_list = tree.xpath('//div[@class="slist"]/ul/li/a')
          for a in a_list:
              img_src = 'http://pic.netbian.com'+a.xpath('./img/@src')[0]
              img_name = a.xpath('./b/text()')[0]
              img_name = img_name.encode('iso-8859-1').decode('gbk')
              img_data = requests.get(img_src,headers=headers).content
              imgPath = dirName+'/'+img_name+'.jpg'
              with open(imgPath,'wb') as fp:
                  fp.write(img_data)
                  print(img_name,'下載成功!!!')
      #http://pic.netbian.com/4kmeinv/中文亂碼的處理

    • 有時候網頁變化莫測 ,即同一個位置的標籤有兩種或兩種以上的寫法 會對爬蟲爬取的規律性造成巨大麻煩
    • 可以用下面的方法來解決一下
    • #https://www.aqistudy.cn/historydata/
      page_text = requests.get('https://www.aqistudy.cn/historydata/',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()')
      cities = tree.xpath('//div[@class="bottom"]/ul/div[2]/li/a/text() | //div[@class="bottom"]/ul/li/a/text()') #提高xpath的通用性
      cities
      所有城市名稱

      • 上面的程式碼是這麼寫的cities = tree.xpath('//div[@class="bottom"]/ul/div[2]/li/a/text() | //div[@class="bottom"]/ul/li/a/text()')
      • 增加了 | 來並列兩個表示式 ,即滿足第一個表示式則 第二個表示式忽略,第一個不滿足,即用第二個表示式!

### 回顧- requests作用:模擬瀏覽器發起請求- urllib:requests的前身- requests模組的編碼流程: - 指定url - 發起請求: - get(url,params,headers) - post(url,data,headers) - 獲取響應資料 - 持久化儲存 - 引數動態化: - 有些情況下我們是需要將請求引數進行更改。將get或者post請求對應的請求引數封裝到一個字典(鍵值對==請求引數)中,然後將改字典作用到get方法的params引數中或者作用到psot方法的data引數中- UA檢測(反爬機制): - 什麼是UA:請求載體的身份標識。伺服器端會檢測請求的UA來鑑定其身份。 - 反反爬策略:UA偽裝。通過抓包工具捕獲某一款瀏覽器的UA值,封裝到字典中,且將該字典作用到headers引數中- 動態載入的資料 - 通過另一個單獨的請求請求到的資料- 如果我們要對一個陌生的網站進行指定資料的爬取? - 首先要確定爬取的資料在改網站中是否為動態載入的 - 是:通過抓包工具實現全域性搜尋,定位動態載入資料對應的資料包,從資料包中提取請求的url和請求引數。 - 不是:就可以直接將瀏覽器位址列中的網址作為我們requests請求的url