1. 程式人生 > >Python爬蟲入門教程 4-100 美空網未登錄圖片爬取

Python爬蟲入門教程 4-100 美空網未登錄圖片爬取

表數 價值 圖片下載 開發 所有圖片 mpi focus .data data

簡介

上一篇寫的時間有點長了,接下來繼續把美空網的爬蟲寫完,這套教程中編寫的爬蟲在實際的工作中可能並不能給你增加多少有價值的技術點,因為它只是一套入門的教程,老鳥你自動繞過就可以了,或者帶帶我也行。

爬蟲分析

首先,我們已經爬取到了N多的用戶個人主頁,我通過鏈接拼接獲取到了

http://www.moko.cc/post/da39db43246047c79dcaef44c201492d/list.html

技術分享圖片

在這個頁面中,咱們要找幾個核心的關鍵點,發現平面拍攝點擊進入的是圖片列表頁面。
接下來開始代碼走起。

獲取所有列表頁面

我通過上篇博客已經獲取到了70000(實際測試50000+)用戶數據,讀取到python中。

這個地方,我使用了一個比較好用的python庫pandas,大家如果不熟悉,先模仿我的代碼就可以了,我把註釋都寫完整。

import pandas as pd

# 用戶圖片列表頁模板
user_list_url = "http://www.moko.cc/post/{}/list.html"
# 存放所有用戶的列表頁
user_profiles = []

def read_data():
    # pandas從csv裏面讀取數據
    df = pd.read_csv("./moko70000.csv")   #文件在本文末尾可以下載
    # 去掉昵稱重復的數據
    df = df.drop_duplicates(["nikename"])
    # 按照粉絲數目進行降序
    profiles = df.sort_values("follows", ascending=False)["profile"]

    for i in profiles:
        # 拼接鏈接
        user_profiles.append(user_list_url.format(i))

if __name__ == ‘__main__‘:
    read_data()
    print(user_profiles)

數據已經拿到,接下來我們需要獲取圖片列表頁面,找一下規律,看到重點的信息如下所示,找對位置,就是正則表達式的事情了。

技術分享圖片
快速的編寫一個正則表達式
<p class="title"><a hidefocus="ture".*?href="(.*?)" class="mwC u">.*?\((\d+?)\)</a></p>

引入re,requests模塊

import requests
import re
# 獲取圖片列表頁面
def get_img_list_page():
    # 固定一個地址,方便測試
    test_url = "http://www.moko.cc/post/da39db43246047c79dcaef44c201492d/list.html"
    response = requests.get(test_url,headers=headers,timeout=3)
    page_text = response.text
    pattern = re.compile(‘<p class="title"><a hidefocus="ture".*?href="(.*?)" class="mwC u">.*?\((\d+?)\)</a></p>‘)
    # 獲取page_list
    page_list = pattern.findall(page_text)

運行得到結果

[(‘/post/da39db43246047c79dcaef44c201492d/category/304475/1.html‘, ‘85‘), (‘/post/da39db43246047c79dcaef44c201492d/category/304476/1.html‘, ‘2‘), (‘/post/da39db43246047c79dcaef44c201492d/category/304473/1.html‘, ‘0‘)]

繼續完善代碼,我們發現上面獲取的數據,有"0"的產生,需要過濾掉

# 獲取圖片列表頁面
def get_img_list_page():
    # 固定一個地址,方便測試
    test_url = "http://www.moko.cc/post/da39db43246047c79dcaef44c201492d/list.html"
    response = requests.get(test_url,headers=headers,timeout=3)
    page_text = response.text
    pattern = re.compile(‘<p class="title"><a hidefocus="ture".*?href="(.*?)" class="mwC u">.*?\((\d+?)\)</a></p>‘)
    # 獲取page_list
    page_list = pattern.findall(page_text)
    # 過濾數據
    for page in page_list:
        if page[1] == ‘0‘:
            page_list.remove(page)
    print(page_list)

獲取到列表頁的入口,下面就要把所有的列表頁面全部拿到了,這個地方需要點擊下面的鏈接查看一下

http://www.moko.cc/post/da39db43246047c79dcaef44c201492d/category/304475/1.html

本頁面有分頁,4頁,每頁顯示數據4*7=28
所以,基本計算公式為 math.ceil(85/28)
接下來是鏈接生成了,我們要把上面的鏈接,轉換成

http://www.moko.cc/post/da39db43246047c79dcaef44c201492d/category/304475/1.html
http://www.moko.cc/post/da39db43246047c79dcaef44c201492d/category/304475/2.html
http://www.moko.cc/post/da39db43246047c79dcaef44c201492d/category/304475/3.html
http://www.moko.cc/post/da39db43246047c79dcaef44c201492d/category/304475/4.html
    page_count =  math.ceil(int(totle)/28)+1
    for i in range(1,page_count):
        # 正則表達式進行替換
        pages = re.sub(r‘\d+?\.html‘,str(i)+".html",start_page)
        all_pages.append(base_url.format(pages))

當我們回去到足夠多的鏈接之後,對於初學者,你可以先幹這麽一步,把這些鏈接存儲到一個csv文件中,方便後續開發

# 獲取所有的頁面
def get_all_list_page(start_page,totle):

    page_count =  math.ceil(int(totle)/28)+1
    for i in range(1,page_count):
        pages = re.sub(r‘\d+?\.html‘,str(i)+".html",start_page)
        all_pages.append(base_url.format(pages))

    print("已經獲取到{}條數據".format(len(all_pages)))
    if(len(all_pages)>1000):
        pd.DataFrame(all_pages).to_csv("./pages.csv",mode="a+")
        all_pages.clear()

讓爬蟲飛一會,我這邊拿到了80000+條數據

技術分享圖片
好了,列表數據有了,接下來,我們繼續操作這個數據,是不是感覺速度有點慢,代碼寫的有點LOW,好吧,我承認這是給新手寫的其實就是懶,我回頭在用一篇文章把他給改成面向對象和多線程的

技術分享圖片

我們接下來基於爬取到的數據再次進行分析

例如 http://www.moko.cc/post/nimusi/category/31793/1.html 這個頁面中,我們需要獲取到,紅色框框的地址,為什麽要或者這個?因為點擊這個圖片之後進入裏面才是完整的圖片列表。
技術分享圖片
我們還是應用爬蟲獲取
幾個步驟

  1. 循環我們剛才的數據列表
  2. 抓取網頁源碼
  3. 正則表達式匹配所有的鏈接
def read_list_data():
    # 讀取數據
    img_list = pd.read_csv("./pages.csv",names=["no","url"])["url"]

    # 循環操作數據
    for img_list_page in img_list:
        try:
            response = requests.get(img_list_page,headers=headers,timeout=3)
        except Exception as e:
            print(e)
            continue
        # 正則表達式獲取圖片列表頁面
        pattern = re.compile(‘<a hidefocus="ture" alt="(.*?)".*? href="(.*?)".*?>VIEW MORE</a>‘)
        img_box = pattern.findall(response.text)

        need_links = []  # 待抓取的圖片文件夾
        for img in img_box:
            need_links.append(img)

            # 創建目錄
            file_path = "./downs/{}".format(str(img[0]).replace(‘/‘, ‘‘))

            if not os.path.exists(file_path):
                os.mkdir(file_path)  # 創建目錄

        for need in need_links:
            # 獲取詳情頁面圖片鏈接
            get_my_imgs(base_url.format(need[1]), need[0])

上面代碼幾個重點地方

        pattern = re.compile(‘<a hidefocus="ture" alt="(.*?)".*? href="(.*?)".*?>VIEW MORE</a>‘)
        img_box = pattern.findall(response.text)

        need_links = []  # 待抓取的圖片文件夾
        for img in img_box:
            need_links.append(img)

獲取到抓取目錄,這個地方,我匹配了兩個部分,主要用於創建文件夾
創建文件夾需要用到 os 模塊,記得導入一下

            # 創建目錄
            file_path = "./downs/{}".format(str(img[0]).replace(‘/‘, ‘‘))

            if not os.path.exists(file_path):
                os.mkdir(file_path)  # 創建目錄

獲取到詳情頁面圖片鏈接之後,在進行一次訪問抓取所有圖片鏈接

#獲取詳情頁面數據
def get_my_imgs(img,title):
    print(img)
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"}
    response = requests.get(img, headers=headers, timeout=3)
    pattern = re.compile(‘<img src2="(.*?)".*?>‘)
    all_imgs = pattern.findall(response.text)
    for download_img in all_imgs:
        downs_imgs(download_img,title)

最後編寫一個圖片下載的方法,所有的代碼完成,圖片保存本地的地址,用的是時間戳。


def downs_imgs(img,title):

    headers ={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"}
    response = requests.get(img,headers=headers,timeout=3)
    content = response.content
    file_name = str(int(time.time()))+".jpg"
    file = "./downs/{}/{}".format(str(title).replace(‘/‘,‘‘).strip(),file_name)
    with open(file,"wb+") as f:
        f.write(content)

    print("完畢")

運行代碼,等著收圖

技術分享圖片

代碼運行一下,發現報錯了
技術分享圖片
原因是路徑的問題,在路徑中出現了...這個特殊字符,我們需要類似上面處理/的方式處理一下。自行處理一下吧。

數據獲取到,就是這個樣子的

技術分享圖片

代碼中需要完善的地方

  1. 代碼分成了兩部分,並且是面向過程的,非常不好,需要改進
  2. 網絡請求部分重復代碼過多,需要進行抽象,並且加上錯誤處理,目前是有可能報錯的
  3. 代碼單線程,效率不高,可以參照前兩篇文章進行改進
  4. 沒有模擬登錄,最多只能爬取6個圖片,這也是為什麽先把數據保存下來的原因,方便後期直接改造

github代碼地址與csv地址

Python爬蟲入門教程 4-100 美空網未登錄圖片爬取