Python爬蟲入門教程 2-100 Python快速爬取妹子圖網站,show

X圖片網站----前言

陷於文章審覈要求,文章中所有妹子圖相關內容,都替換成X圖片

所有網站相關鏈接,都整體進行X替換,如需要確定網址,可以查閱https://www.cnblogs.com/happymeng/p/10112374.html該網址獲取

從今天開始就要擼起袖子,直接寫Python爬蟲了,學習語言最好的辦法就是有目的的進行,所以,接下來我將用10+篇的博客,寫爬圖片這一件事情。希望可以做好。

爲了寫好爬蟲,我們需要準備一個火狐瀏覽器,還需要準備抓包工具,抓包工具,我使用的是CentOS自帶的tcpdump,加上wireshark ,這兩款軟件的安裝和使用,建議你還是學習一下,後面我們應該會用到。

X圖片網站---- 網絡請求模塊requests

Python中的大量開源的模塊使得編碼變的特別簡單,我們寫爬蟲第一個要了解的模塊就是requests。

X圖片網站---- 安裝requests

打開終端:使用命令

pip3 install requests

等待安裝完畢即可使用

接下來在終端中鍵入如下命令

# mkdir demo  
# cd demo
# touch down.py

上面的linux命令是 創建一個名稱爲demo的文件夾,之後創建一個down.py文件,你也可以使用GUI工具,像操作windows一樣,右鍵創建各種文件。

爲了提高在linux上的開發效率,我們需要安裝一個visual studio code 的開發工具

對於怎麼安裝vscode,參考官方的https://code.visualstudio.com/docs/setup/linux 有詳細的說明。

對於centos則如下:

sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
sudo sh -c 'echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/vscode.repo'

然後用yum命令安裝

yum check-update
sudo yum install code

安裝成功之後,在你的CentOS中會出現如下畫面

這裏寫圖片描述

接着說我們上面的操作 ,因爲我們這邊是用gnome圖形界面,所以後面的有些操作,我直接用windows的操作風格講解了

打開軟件>文件>打開文件>找到我們剛剛創建的down.py文件

之後,在VSCODE裏面輸入


import requests   #導入模塊

def run():        #聲明一個run方法
    print("跑碼文件")    #打印內容

if __name__ == "__main__":   #主程序入口
    run()    #調用上面的run方法
        

tips:本教程不是Python3的基礎入門課,所以有些編碼基礎,默認你懂,比如Python沒有分號結尾,需要對齊格式。我會盡量把註釋寫的完整

按鍵盤上的ctrl+s保存文件,如果提示權限不足,那麼按照提示輸入密碼即可

通過終端進入demo目錄,然後輸入

python3 down.py

顯示如下結果,代表編譯沒有問題

[root@bogon demo]# python3 down.py
跑碼文件

接下來,我們開始測試requests模塊是否可以使用

修改上述代碼中的


import requests

def run():
    response = requests.get("http://www.baidu.com")
    print(response.text)

if __name__ == "__main__":
    run()
        

運行結果(出現下圖代表你運行成功了):

這裏寫圖片描述

接下來,我們實際下載一張圖片試試,比如下面這張圖片

因爲問題會導致該圖無法顯示

修改代碼,在這之前,我們修改一些內容

由於每次修改文件,都提示必須管理員權限,所以你可以使用linux命令修改權限。

[root@bogon linuxboy]# chmod -R 777 demo/


import requests

def run():
    response = requests.get("http://測試圖片.jpg") 
    with open("xxx.jpg","wb") as f :
        f.write(response.content)   
        f.close

if __name__ == "__main__":
    run()

運行代碼之後,發現在文件夾內部生成了一個文件

在這裏插入圖片描述
但是打開文件之後發現,這個文件並不能查閱,這代表這個文件壓根沒有下載下來

在這裏插入圖片描述

我們繼續修改代碼,因爲有的服務器圖片,都做了一些限制,我們可以用瀏覽器打開,但是使用Python代碼並不能完整的下載下來。

修改代碼


import requests

def run():
    # 頭文件,header是字典類型
    headers = {
        "Host":"www.newsimg.cn",
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5383.400 QQBrowser/10.0.1313.400"
    }
    response = requests.get("http://測試圖片.jpg",headers=headers) 
    with open("xxx.jpg","wb") as f :
        f.write(response.content)   
        f.close()

if __name__ == "__main__":
    run()
        

好了,這次在終端編譯一下python文件

python3 down.py

發現圖片下載下來了

我們重點查看上述代碼中 requests.get部分,添加了一個headers的實參。這樣我們程序就下載下來了完整的圖片。

X圖片圖網站---- Python爬蟲頁面分析

有了上面這個簡單的案例,我們接下來的操作就變的簡單多了。爬蟲是如何進行的呢?

輸入域名->下載源代碼->分析圖片路徑->下載圖片

上面就是他的步驟

輸入域名

我們今天要爬的網站叫做 http://www.mztu.com/a/pure.html

爲啥爬取這個網站,因爲好爬。

好了,接下來分析這個頁面

頁面元素不好展示,大家自行查閱吧

在這裏插入圖片描述

做爬蟲很重要的一點,就是你要找到分頁的地方,因爲有分頁代表着有規律,有規律,我們就好爬了(可以做的更智能一些,輸入首頁網址,爬蟲自己就能分析到這個網站中的所有地址)

上面圖片中,我們發現了分頁,那麼找規律吧

這裏寫圖片描述

使用火狐瀏覽器的開發者工具,發現分頁規律

http://www.mztu.com/a/pure_1.html
http://www.mztu.com/a/pure_2.html
http://www.mztu.com/a/pure_3.html
http://www.mztu.com/a/pure_4.html

好了,接下來用Python實現這部分(以下寫法有部分面向對象的寫法,沒有基礎的同學,請百度找些基礎來看,不過對於想學習的你來說,這些簡單極了)


import requests
all_urls = []  #我們拼接好的圖片集和列表路徑
class Spider():
    #構造函數,初始化數據使用
    def __init__(self,target_url,headers):
        self.target_url = target_url
        self.headers = headers

    #獲取所有的想要抓取的URL
    def getUrls(self,start_page,page_num):
        
        global all_urls
        #循環得到URL
        for i in range(start_page,page_num+1):
            url = self.target_url  % i
            all_urls.append(url)

if __name__ == "__main__":
    headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0',
            'HOST':'www.mztu.com'
    }
    target_url = 'http://www.mztu.com/a/pure_%d.html' #圖片集和列表規則
    
    spider = Spider(target_url,headers)
    spider.getUrls(1,16)
    print(all_urls)
        

上面的代碼,可能需要有一定的Python基礎可以看懂,不過你其實仔細看一下,就幾個要點

第一個是 class Spider(): 我們聲明瞭一個類,然後我們使用 def __init__去聲明一個構造函數,這些我覺得你找個教程30分鐘也就學會了。

拼接URL,我們可以用很多辦法,我這裏用的是最直接的,字符串拼接。

注意上述代碼中有一個全局的變量 all_urls 我用它來存儲我們的所有分頁的URL

接下來,是爬蟲最核心的部分代碼了

我們需要分析頁面中的邏輯。首先打開 http://www.mztu.com/a/pure_1.html,右鍵審查元素。

這裏寫圖片描述

在這裏插入圖片描述

發現上圖紅色框框裏面的鏈接

點擊圖片之後,發現進入一個圖片詳情頁面,發現竟然是一組圖片,那麼現在的問題是

我們要解決第一步,需要在 http://www.mztu.com/a/pure_1.html 這種頁面中爬取所有的 http://www.mztu.com/a/5585.html 這種地址

這裏我們採用多線程的方式爬取(這裏還用了一種設計模式,叫觀察者模式)

import threading   #多線程模塊
import re #正則表達式模塊
import time #時間模塊

首先引入三個模塊,分別是多線程,正則表達式,時間模塊

新增加一個全局的變量,並且由於是多線程操作,我們需要引入線程鎖

all_img_urls = []       #圖片列表頁面的數組

g_lock = threading.Lock()  #初始化一個鎖  

聲明一個生產者的類,用來不斷的獲取圖片詳情頁地址,然後添加到 all_img_urls 這個全局變量中


#生產者,負責從每個頁面提取圖片列表鏈接
class Producer(threading.Thread):   

    def run(self):
        headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0',
            'HOST':'www.mztu.com'
        }
        global all_urls
        while len(all_urls) > 0 :
            g_lock.acquire()  #在訪問all_urls的時候,需要使用鎖機制
            page_url = all_urls.pop()   #通過pop方法移除最後一個元素,並且返回該值
            
            g_lock.release() #使用完成之後及時把鎖給釋放,方便其他線程使用
            try:
                print("分析"+page_url)   
                response = requests.get(page_url , headers = headers,timeout=3)
                all_pic_link = re.findall('<a target=\'_blank\' href="(.*?)">',response.text,re.S)   
                global all_img_urls
                g_lock.acquire()   #這裏還有一個鎖
                all_img_urls += all_pic_link   #這個地方注意數組的拼接,沒有用append直接用的+=也算是python的一個新語法吧
                print(all_img_urls)
                g_lock.release()   #釋放鎖
                time.sleep(0.5)
            except:
                pass


上述代碼用到了繼承的概念,我從threading.Thread中繼承了一個子類,繼承的基礎學習,你可以去翻翻 http://www.runoob.com/python3/python3-class.html 菜鳥教程就行。

線程鎖,在上面的代碼中,當我們操作all_urls.pop()的時候,我們是不希望其他線程對他進行同時操作的,否則會出現意外,所以我們使用g_lock.acquire()鎖定資源,然後使用完成之後,記住一定要立馬釋放g_lock.release(),否則這個資源就一直被佔用着,程序無法進行下去了。

匹配網頁中的URL,我使用的是正則表達式,後面我們會使用其他的辦法,進行匹配。

re.findall()方法是獲取所有匹配到的內容,正則表達式,你可以找一個30分鐘入門的教程,看看就行。

代碼容易出錯的地方,我放到了

try: except: 裏面,當然,你也可以自定義錯誤。

如果上面的代碼,都沒有問題,那麼我們就可以在程序入口的地方編寫

for x in range(2):
    t = Producer()
    t.start()
        

執行程序,因爲我們的Producer繼承自threading.Thread類,所以,你必須要實現的一個方法是 def run 這個我相信在上面的代碼中,你已經看到了。然後我們可以執行啦~~~

運行結果:

在這裏插入圖片描述

這樣,圖片詳情頁面的列表就已經被我們存儲起來了。

接下來,我們需要執行這樣一步操作,我想要等待圖片詳情頁面全部獲取完畢,在進行接下來的分析操作。

這裏增加代碼

#threads= []   
#開啓兩個線程去訪問
for x in range(2):
    t = Producer()
    t.start()
    #threads.append(t)

# for tt in threads:
#     tt.join()

print("進行到我這裏了")


註釋關鍵代碼,運行如下

[linuxboy@bogon demo]$ python3 down.py
分析http://www.mztu.com/a/pure_2.html
分析http://www.mztu.com/a/pure_1.html
進行到我這裏了
['http://www.mztu.com/a/5585.html', 

把上面的tt.join等代碼註釋打開

[linuxboy@bogon demo]$ python3 down.py
分析http://www.mztu.com/a/pure_2.html
分析http://www.mztu.com/a/pure_1.html
['http://www.mztu.com/a/5429.html', ......
進行到我這裏了

發現一個本質的區別,就是,我們由於是多線程的程序,所以,當程序跑起來之後,print("進行到我這裏了")不會等到其他線程結束,就會運行到,但是當我們改造成上面的代碼之後,也就是加入了關鍵的代碼 tt.join() 那麼主線程的代碼會等到所以子線程運行完畢之後,在接着向下運行。這就滿足了,我剛纔說的,先獲取到所有的圖片詳情頁面的集合,這一條件了。

join所完成的工作就是線程同步,即主線程遇到join之後進入阻塞狀態,一直等待其他的子線程執行結束之後,主線程在繼續執行。這個大家在以後可能經常會碰到。

下面編寫一個消費者/觀察者,也就是不斷關注剛纔我們獲取的那些圖片詳情頁面的數組。

添加一個全局變量,用來存儲獲取到的圖片鏈接

pic_links = []            #圖片地址列表

#消費者
class Consumer(threading.Thread) : 
    def run(self):
        headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0',
            'HOST':'www.mztu.com'
        }
        global all_img_urls   #調用全局的圖片詳情頁面的數組
        print("%s is running " % threading.current_thread)
        while len(all_img_urls) >0 : 
            g_lock.acquire()
            img_url = all_img_urls.pop()
            g_lock.release()
            try:
                response = requests.get(img_url , headers = headers )
                response.encoding='gb2312'   #由於我們調用的頁面編碼是GB2312,所以需要設置一下編碼
                title = re.search('<title>(.*?) | X圖片圖</title>',response.text).group(1)
                all_pic_src = re.findall('<img alt=.*?src="(.*?)" /><br />',response.text,re.S)
                
                pic_dict = {title:all_pic_src}   #python字典
                global pic_links
                g_lock.acquire()
                pic_links.append(pic_dict)    #字典數組
                print(title+" 獲取成功")
                g_lock.release()
                
            except:
                pass
            time.sleep(0.5)


看到沒有,上面的代碼其實和我們剛纔寫的極其相似,後面,我會在github上面把這部分代碼修改的更加簡潔一些,不過這纔是第二課,後面我們的路長着呢。

代碼中比較重要的一些部分,我已經使用註釋寫好了,大家可以直接參考。大家一定要注意我上面使用了兩個正則表達式,分別用來匹配title和圖片的url這個title是爲了後面創建不同的文件夾使用的,所以大家注意吧。

#開啓10個線程去獲取鏈接
for x in range(10):
    ta = Consumer()
    ta.start()

運行結果:

[linuxboy@bogon demo]$ python3 down.py
分析http://www.mztu.com/a/pure_2.html
分析http://www.mztu.com/a/pure_1.html
['http://www.mztu.com/a/5585.html', ......
<function current_thread at 0x7f7caef851e0> is running 
<function current_thread at 0x7f7caef851e0> is running 
<function current_thread at 0x7f7caef851e0> is running 
<function current_thread at 0x7f7caef851e0> is running 
<function current_thread at 0x7f7caef851e0> is running 
<function current_thread at 0x7f7caef851e0> is running 
<function current_thread at 0x7f7caef851e0> is running 
<function current_thread at 0x7f7caef851e0> is running 
進行到我這裏了
<function current_thread at 0x7f7caef851e0> is running 
<function current_thread at 0x7f7caef851e0> is running 



在這裏插入圖片描述
是不是感覺距離成功有進了一大步

接下來就是,我們開篇提到的那個存儲圖片的操作了,還是同樣的步驟,寫一個自定義的類

class DownPic(threading.Thread) :

    def run(self):
        headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0',
            'HOST':'mm.chinasareview.com'
        
        }
        while True:   #  這個地方寫成死循環,爲的是不斷監控圖片鏈接數組是否更新
            global pic_links
            # 上鎖
            g_lock.acquire()
            if len(pic_links) == 0:   #如果沒有圖片了,就解鎖
                # 不管什麼情況,都要釋放鎖
                g_lock.release()
                continue
            else:
                pic = pic_links.pop()
                g_lock.release()
                # 遍歷字典列表
                for key,values in  pic.items():
                    path=key.rstrip("\\")
                    is_exists=os.path.exists(path)
                    # 判斷結果
                    if not is_exists:
                        # 如果不存在則創建目錄
                        # 創建目錄操作函數
                        os.makedirs(path) 
                
                        print (path+'目錄創建成功')
                        
                    else:
                        # 如果目錄存在則不創建,並提示目錄已存在
                        print(path+' 目錄已存在') 
                    for pic in values :
                        filename = path+"/"+pic.split('/')[-1]
                        if os.path.exists(filename):
                            continue
                        else:
                            response = requests.get(pic,headers=headers)
                            with open(filename,'wb') as f :
                                f.write(response.content)
                                f.close


我們獲取圖片鏈接之後,就需要下載了,我上面的代碼是首先創建了一個之前獲取到title的文件目錄,然後在目錄裏面通過下面的代碼,去創建一個文件。

涉及到文件操作,引入一個新的模塊

import os  #目錄操作模塊

# 遍歷字典列表
for key,values in  pic.items():
    path=key.rstrip("\\")
    is_exists=os.path.exists(path)
    # 判斷結果
    if not is_exists:
        # 如果不存在則創建目錄
        # 創建目錄操作函數
        os.makedirs(path) 

        print (path+'目錄創建成功')
        
    else:
        # 如果目錄存在則不創建,並提示目錄已存在
        print(path+' 目錄已存在') 
    for pic in values :
        filename = path+"/"+pic.split('/')[-1]
        if os.path.exists(filename):
            continue
        else:
            response = requests.get(pic,headers=headers)
            with open(filename,'wb') as f :
                f.write(response.content)
                f.close

因爲我們的圖片鏈接數組,裏面存放是的字典格式,也就是下面這種格式


[{"妹子圖1":["http://mm.chinasareview.com/wp-content/uploads/2016a/08/24/01.jpg","http://mm.chinasareview.com/wp-content/uploads/2016a/08/24/02.jpg"."http://mm.chinasareview.com/wp-content/uploads/2016a/08/24/03.jpg"]},{"妹子圖2":["http://mm.chinasareview.com/wp-content/uploads/2016a/08/24/01.jpg","http://mm.chinasareview.com/wp-content/uploads/2016a/08/24/02.jpg"."http://mm.chinasareview.com/wp-content/uploads/2016a/08/24/03.jpg"]},{"妹子圖3":["http://mm.chinasareview.com/wp-content/uploads/2016a/08/24/01.jpg","http://mm.chinasareview.com/wp-content/uploads/2016a/08/24/02.jpg"."http://mm.chinasareview.com/wp-content/uploads/2016a/08/24/03.jpg"]}]

需要先循環第一層,獲取title,創建目錄之後,在循環第二層去下載圖片,代碼中,我們在修改一下,把異常處理添加上。

try:
    response = requests.get(pic,headers=headers)
    with open(filename,'wb') as f :
        f.write(response.content)
        f.close
except Exception as e:
    print(e)
    pass


然後在主程序中編寫代碼


#開啓10個線程保存圖片
for x in range(10):
    down = DownPic()
    down.start()
        

運行結果:


[linuxboy@bogon demo]$ python3 down.py
分析http://www.mztu.com/a/pure_2.html
分析http://www.mztu.com/a/pure_1.html
['http://www.mztu.com/a/5585.html', 'http://www.mztu.com/a/5577.html', 'http://www.mztu.com/a/5576.html', 'http://www.mztu.com/a/5574.html', 'http://www.mztu.com/a/5569.html', .......
<function current_thread at 0x7fa5121f2268> is running 
<function current_thread at 0x7fa5121f2268> is running 
<function current_thread at 0x7fa5121f2268> is running 
進行到我這裏了



在這裏插入圖片描述

文件目錄下面同時出現

點開一個目錄

這裏寫圖片描述

好了,今天的一個簡單的爬蟲成了

最後我們在代碼的頭部寫上

# -*- coding: UTF-8 -*-   

防止出現 Non-ASCII character 'xe5' in file報錯問題。

歡迎關注「非本科程序員」 回覆 【妹子圖】獲取資源

掃碼關注非本科程序員

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章