為避免尬聊威蕉,我竟爬取了兩千多張斗圖

大家好,我是啃書(shū)君橄仍。

前幾天和女神聊天的時(shí)候?qū)嵲谑翘瘟巳驼牵驗(yàn)闆](méi)有足夠的斗圖表情包,整個(gè)聊天的氣氛都帶動(dòng)不起來(lái)侮繁,所以抑郁不得志虑粥!

為了追到心目中的完美女神,我爬了一千多張斗圖表情包宪哩,只為下一次聊天的時(shí)候娩贷,主動(dòng)權(quán)都在我的手上。

考慮到有些小伙伴可能在python基礎(chǔ)不是很好斋射,因此育勺,啃書(shū)君決定先幫各位補(bǔ)補(bǔ)基礎(chǔ)知識(shí)但荤,大佬可以直接看實(shí)戰(zhàn)內(nèi)容罗岖。本次實(shí)戰(zhàn)內(nèi)容是爬取:斗圖吧腹躁。

面向?qū)ο?/h1>

python從設(shè)計(jì)開(kāi)始就是一門(mén)面向?qū)ο蟮牡恼Z(yǔ)言桑包,因此使用python創(chuàng)建一個(gè)類(lèi)與對(duì)象是非常簡(jiǎn)單的一件事情。

如果你以前沒(méi)有接觸過(guò)面向?qū)ο蟮木幊陶Z(yǔ)言纺非,那么你需要了解一些面向?qū)ο笳Z(yǔ)言的一些基本特征哑了,接下來(lái)就來(lái)感受python的面向?qū)ο笳Z(yǔ)言赘方。

面向?qū)ο蠛?jiǎn)介

  • 類(lèi)(Class):用來(lái)描述具有相同的屬性和方法的對(duì)象的集合。它定義了該集合中每個(gè)對(duì)象所共有的屬性和方法弱左。對(duì)象是類(lèi)的實(shí)例窄陡。
  • 類(lèi)變量:類(lèi)變量在整個(gè)實(shí)例化的對(duì)象中是公共的。類(lèi)變量定義在類(lèi)中拆火,且在函數(shù)體外跳夭。
  • 數(shù)據(jù)成員:類(lèi)變量或?qū)嵗兞浚糜谔幚眍?lèi)及其實(shí)例對(duì)象的相關(guān)數(shù)據(jù)们镜。
  • 方法重載:如果從父類(lèi)繼承的方法币叹,無(wú)法滿足子類(lèi)的需求,可以對(duì)其進(jìn)行改寫(xiě)模狭,這個(gè)過(guò)程叫做覆蓋颈抚,也稱(chēng)為方法的重載。
  • 實(shí)例變量:定義在方法中的變量嚼鹉,只作用于當(dāng)前實(shí)例的類(lèi)贩汉。
  • 繼承:即一個(gè)派生類(lèi),繼承基類(lèi)(父類(lèi))的字段與方法锚赤。
  • 實(shí)例化:創(chuàng)建一個(gè)實(shí)例雾鬼,類(lèi)的具體對(duì)象。
  • 方法:類(lèi)中定義的函數(shù)
  • 對(duì)象:通過(guò)類(lèi)定義的數(shù)據(jù)結(jié)構(gòu)實(shí)例宴树。對(duì)象包括兩個(gè)數(shù)據(jù)成員(類(lèi)變量和實(shí)例變量)和方法策菜。

創(chuàng)建類(lèi)與對(duì)象

類(lèi)相當(dāng)于一個(gè)模板,模板里面可以有多個(gè)函數(shù)酒贬,函數(shù)用于實(shí)現(xiàn)功能又憨。

對(duì)象其實(shí)是根據(jù)模板創(chuàng)建的一個(gè)實(shí)例,通過(guò)創(chuàng)建的實(shí)例可以執(zhí)行類(lèi)中的函數(shù)锭吨。

# 創(chuàng)建類(lèi)
class Foo(object):
    # 創(chuàng)建類(lèi)中的函數(shù)
    def bar(self):
        # todo
        pass
 # 根據(jù)Foo類(lèi)創(chuàng)建對(duì)象obj
 obj = Foo()
  • class是關(guān)鍵字蠢莺,代表類(lèi)
  • object代碼父類(lèi),所有類(lèi)都繼承object類(lèi)
  • 創(chuàng)建對(duì)象零如,類(lèi)名稱(chēng)后加上括號(hào)即可

面向?qū)ο蟮娜筇匦?/h1>

封裝

封裝躏将,顧名思義就是將內(nèi)容封裝到某個(gè)地方,以后再去調(diào)用被封裝在某處的內(nèi)容考蕾。

所以祸憋,在使用面向?qū)ο蟮姆庋b特性時(shí),需要:

  • 將內(nèi)容封裝到某處
  • 從某處調(diào)用被封裝的內(nèi)容
class Foo(object):
    # 構(gòu)造方法肖卧,根據(jù)類(lèi)創(chuàng)建對(duì)象時(shí)自動(dòng)執(zhí)行
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
# 根據(jù)類(lèi)Foo創(chuàng)建對(duì)象
# 自動(dòng)啟動(dòng)Foo類(lèi)的__init__方法
obj1 = Foo('Jack', 18)
obj2 = Fo('Rose', 20)

obj1 = Foo('Jack', 18) 將Jack和18分別封裝到obj1(self)的name和age屬性中蚯窥,obj2也是同樣的道理。

self是一個(gè)形式參數(shù),當(dāng)執(zhí)行obj1 = Foo('Jack', 18) 拦赠,self等于obj1巍沙,因此,每個(gè)對(duì)象都有name和age屬性荷鼠。

通過(guò)對(duì)象調(diào)用封裝內(nèi)容

class Foo(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
obj1 = Foo('Jack', 18)
print(obj1.name)    # 調(diào)用obj1的name屬性
print(obj1.age)     # 調(diào)用obj1的age屬性

obj2 = Foo('Jack', 18)
print(obj2.name)    # 調(diào)用obj2的name屬性
print(obj2.age)     # 調(diào)用obj2的age屬性

通過(guò)self間接調(diào)用封裝的內(nèi)容

class Foo(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def detail(self):
        print(self.name)
        print(self.age)

obj1 = Foo('Jack', 18)
obj1.detail()

obj2 = Foo('Rose', 20)
obj2.detail()

obj1.detail() python默認(rèn)會(huì)將obj1傳給self參數(shù)句携,即:obj1.detail(obj1),所以允乐,此時(shí)方法內(nèi)部的self=obj1务甥,即self.name相當(dāng)于obj1.name。

感受面向?qū)ο蟮暮?jiǎn)便

對(duì)于面向?qū)ο蠓庋b來(lái)說(shuō)喳篇,其實(shí)就是使用構(gòu)造方法將內(nèi)容封裝到對(duì)象中敞临,然后通過(guò)對(duì)象直接或者self間接獲取封裝內(nèi)容。

接下來(lái)麸澜,我們就來(lái)體驗(yàn)一下面向?qū)ο蟮暮?jiǎn)便性挺尿。

def kanchai(name, age, gender):
    print "%s,%s歲,%s,上山去砍柴" %(name, age, gender)


def qudongbei(name, age, gender):
    print "%s,%s歲,%s,開(kāi)車(chē)去東北" %(name, age, gender)


def dabaojian(name, age, gender):
    print "%s,%s歲,%s,最?lèi)?ài)大保健" %(name, age, gender)


kanchai('小明', 10, '男')
qudongbei('小明', 10, '男')
dabaojian('小明', 10, '男')


kanchai('老李', 90, '男')
qudongbei('老李', 90, '男')
dabaojian('老李', 90, '男')
函數(shù)式編程
 
class Foo(object):
    
    def __init__(self, name, age ,gender):
        self.name = name
        self.age = age
        self.gender = gender

    def kanchai(self):
        print "%s,%s歲,%s,上山去砍柴" %(self.name, self.age, self.gender)

    def qudongbei(self):
        print "%s,%s歲,%s,開(kāi)車(chē)去東北" %(self.name, self.age, self.gender)

    def dabaojian(self):
        print "%s,%s歲,%s,最?lèi)?ài)大保健" %(self.name, self.age, self.gender)


xiaoming = Foo('小明', 10, '男')
xiaoming.kanchai()
xiaoming.qudongbei()
xiaoming.dabaojian()

laoli = Foo('老李', 90, '男')
laoli.kanchai()
laoli.qudongbei()
laoli.dabaojian()

如果使用函數(shù)式編程,需要在每一個(gè)執(zhí)行函數(shù)的時(shí)候都要傳入相同的參數(shù)炊邦,如果參數(shù)多的話编矾,就每一次都要復(fù)制粘貼,非常不方便馁害;而對(duì)于面向?qū)ο髞?lái)說(shuō)窄俏,只需要在創(chuàng)建對(duì)象時(shí),將所需要的參數(shù)封裝到對(duì)象中碘菜,然后通過(guò)對(duì)象調(diào)用即可獲取封裝的內(nèi)容凹蜈。

繼承

繼承就是讓類(lèi)和類(lèi)之間存在父子關(guān)系,子類(lèi)可以直接訪問(wèn)父類(lèi)的靜態(tài)屬性與方法忍啸。在python中仰坦,新建的類(lèi)可以繼承一個(gè)或多個(gè)父類(lèi),父類(lèi)可以稱(chēng)為基類(lèi)或超類(lèi)计雌,新建的類(lèi)稱(chēng)為派生類(lèi)或子類(lèi)悄晃。

class ParentClass1: #定義父類(lèi)1
    pass
class ParentClass2: #定義父類(lèi)2
    pass
class SubClass1(ParentClass1):
    # 單繼承,基類(lèi)是ParentClass1凿滤,派生類(lèi)是SubClass
    pass
class SubClass2(ParentClass1,ParentClass2):
    # python支持多繼承妈橄,用逗號(hào)分隔開(kāi)多個(gè)繼承的類(lèi)
    pass

print(SubClass1.__bases__)  # 查看所有繼承的父類(lèi)
print(SubClass2.__bases__)
# ===============
# (<class '__main__.Father1'>,)
# (<class '__main__.Father1'>, <class '__main__.Father2'>)

繼承的規(guī)則

1、子類(lèi)繼承父類(lèi)的成員變量與方法

2翁脆、子類(lèi)不繼承父類(lèi)的構(gòu)造方法

3眷蚓、子類(lèi)不能刪除父類(lèi)成員,但是可以重新定義父類(lèi)成員

4鹃祖、子類(lèi)可以增加自己的成員溪椎。

具體代碼,如下所示:

class Person(object):
    def __init__(self, name, age, sex):
        self.name = 'jasn'
        self.age = 18
        self.sex = sex

    def talk(self):
        print('I want to say someting to you')


class Chinese(Person):
    def __init__(self, name, age, sex, language):
        Person.__init__(self, name, age, sex)   # 用父類(lèi)的name, age, sex覆蓋掉子類(lèi)的屬性
        self.age = age # 覆蓋掉父類(lèi)的age屬性恬口,取值為子類(lèi)實(shí)例傳入的age參數(shù)
        self.language = 'Chinese'

    def talk(self):
        print('我說(shuō)的是普通話')
        Person.talk(self)


obj = Chinese('nancy', 30, 'male', '普通話')
print(obj.name)
print(obj.age)
print(obj.language)
obj.talk()

運(yùn)行結(jié)果校读,如下:

jasn
30
Chinese
我說(shuō)的是普通話
I want to say someting to you

因?yàn)椋珻hinese類(lèi)覆蓋了Person類(lèi)祖能,在開(kāi)始的時(shí)候歉秫,我們將父類(lèi)的屬性覆蓋了子類(lèi)的屬性,比如說(shuō)name屬性养铸,子類(lèi)沒(méi)有去覆蓋父類(lèi)雁芙,因此,即使子類(lèi)傳來(lái)了name屬性值钞螟,但依舊還是輸出父類(lèi)的name屬性兔甘。

繼承的作用

1、實(shí)現(xiàn)代碼(功能)重用鳞滨,降低代碼冗余

2洞焙、增強(qiáng)軟件的可擴(kuò)充性

3、提高軟件的維護(hù)性

繼承與抽象的概念

面向?qū)ο蟮膬蓚€(gè)重要概念:抽象與分類(lèi)拯啦。

class animal():   # 定義父類(lèi)
    country = 'china'     # 這個(gè)叫類(lèi)的變量
    def __init__(self,name,age):
        self.name = name   # 這些又叫數(shù)據(jù)屬性
        self.age = age

    def walk(self):         # 類(lèi)的函數(shù)澡匪,方法,動(dòng)態(tài)屬性
        print('%s is walking'%self.name)

    def say(self):
        pass

class people(animal): # 子類(lèi)繼承父類(lèi)
    pass
    
class pig(animal): # 子類(lèi)繼承父類(lèi)
    pass

class dog(animal): # 子類(lèi)繼承父類(lèi)
    pass

aobama=people('aobama',60)   # 實(shí)例化一個(gè)對(duì)象
print(aobama.name)
aobama.walk()

上面的代碼可以這樣理解:我們將人褒链、狗唁情、豬抽象為動(dòng)物,人甫匹、狗甸鸟、豬都繼承動(dòng)物類(lèi)。

python中super()的作用和原理

super()在類(lèi)的繼承里面非常常用兵迅,它解決了子類(lèi)調(diào)用父類(lèi)方法的一些問(wèn)題哀墓。下面我們來(lái)看一下,它優(yōu)化了什么問(wèn)題喷兼。

class Foo(object):
    def bar(self, message):
        print(message)


obj1 = Foo()
obj1.bar('hello')

當(dāng)存在繼承關(guān)系的時(shí)候篮绰,有時(shí)候需要在子類(lèi)中調(diào)用父類(lèi)方法,此時(shí)最簡(jiǎn)單的方法就是把對(duì)象調(diào)用轉(zhuǎn)換成類(lèi)調(diào)用季惯,需要注意的是這時(shí)self參數(shù)需要顯示傳遞吠各。

具體代碼,如下所示:

class FooParent(object):
    """docstring for FooParent"""
    def bar(self, message):
        print(message)

class FooChild(FooParent):
    """docstring for FooChild"""
    def bar(self, message):
        FooParent.bar(self, message)



foochild = FooChild()
foochild.bar('hello')

這樣的繼承方式其實(shí)是存在缺陷的勉抓,比如說(shuō)贾漏,我修改了父類(lèi)的名稱(chēng),那么子類(lèi)中將要涉及多處修改藕筋。

因此python就引入了super()機(jī)制纵散,具體代碼如下所示:

class FooParent(object):
    def bar(self, message):
        print(message)


class FooChild(FooParent):
    def bar(self, message):
        super(FooChild, self).bar(message)


obj = FooChild()
obj.bar('hello')

多態(tài)

關(guān)于python多態(tài)的知識(shí),因本次實(shí)戰(zhàn)內(nèi)容中并沒(méi)有使用到,因此我就不再敘述了伍掀,小伙伴們可以自行查找資料去了解掰茶。

什么是生產(chǎn)者與消費(fèi)者模式

比如有兩個(gè)進(jìn)程A與B,它們共享一個(gè)固定大小的緩沖區(qū)蜜笤,A進(jìn)程生產(chǎn)數(shù)據(jù)放入緩沖區(qū)濒蒋;B進(jìn)程從緩沖區(qū)取出數(shù)據(jù)進(jìn)行計(jì)算,那么這里的A進(jìn)程就相當(dāng)于生產(chǎn)者把兔,B進(jìn)程相當(dāng)于消費(fèi)者沪伙。

為什么要使用生產(chǎn)者與消費(fèi)者模式

在進(jìn)程的世界里,生產(chǎn)者就是生產(chǎn)數(shù)據(jù)的進(jìn)程县好,消費(fèi)者就是使用(處理)數(shù)據(jù)的進(jìn)程围橡。同樣的道理,如果消費(fèi)者的處理能力大于生產(chǎn)者缕贡,那么消費(fèi)者就必須等待生產(chǎn)者某饰。同樣的道理,如果生產(chǎn)者的處理能力大于消費(fèi)者能力善绎,那么生產(chǎn)者就必須等待消費(fèi)者黔漂。

實(shí)現(xiàn)了生產(chǎn)者與消費(fèi)者的解耦和,平衡了生產(chǎn)力與消費(fèi)力禀酱,因?yàn)槎卟荒苤苯訙贤ň媸兀峭ㄟ^(guò)隊(duì)列進(jìn)行溝通。

生產(chǎn)者消費(fèi)者模式

生產(chǎn)者消費(fèi)者模式是通過(guò)一個(gè)容器來(lái)解決生產(chǎn)者和消費(fèi)者的強(qiáng)耦合問(wèn)題剂跟。

生產(chǎn)者與消費(fèi)者不直接通信减途,而是通過(guò)阻塞隊(duì)列進(jìn)行通信,因此曹洽,生產(chǎn)者生產(chǎn)完數(shù)據(jù)之后不用等待消費(fèi)者處理鳍置,直接扔給阻塞隊(duì)列,消費(fèi)者不找生產(chǎn)者要數(shù)據(jù)送淆,而是去阻塞隊(duì)列中找數(shù)據(jù)税产。阻塞隊(duì)列就類(lèi)似于緩沖區(qū),平衡了生產(chǎn)者與消費(fèi)者的能力偷崩。

multiprocess-Queue實(shí)現(xiàn)

具體代碼辟拷,如下所示:

from multiprocessing import Process, Queue
import time, random
from threading import Thread
import queue


# 生產(chǎn)者
def producer(name, food, q):
    for i in range(4):
        time.sleep(random.randint(1, 3))  # 模擬產(chǎn)生數(shù)據(jù)的時(shí)間
        f = '%s 生產(chǎn)了 %s %s個(gè)' % (name, food, i + 1)
        print(f)
        q.put(f)


# 消費(fèi)者
def consumer(name, q):
    while True:
        food = q.get()
        if food is None:
            print('%s 獲取到一個(gè)空' % name)
            break
        f = '%s 消費(fèi)了 %s' % (name, food)
        print(f)
        time.sleep(random.randint(1, 3))


if __name__ == '__main__':
    q = Queue()  # 創(chuàng)建隊(duì)列
    # 模擬生產(chǎn)者,產(chǎn)生數(shù)據(jù)
    p1 = Process(target=producer, args=('p1', '包子', q))
    p1.start()
    p2 = Process(target=producer, args=('p2', '燒餅', q))
    p2.start()

    c1 = Process(target=consumer, args=('c1', q))
    c1.start()
    c2 = Process(target=consumer, args=('c2', q))
    c2.start()

    p1.join()
    p2.join()
    q.put(None)
    q.put(None)

Thread-Queue實(shí)現(xiàn)

上面的代碼是由多進(jìn)程實(shí)現(xiàn)的阐斜,接下來(lái)就考慮一下多線程實(shí)現(xiàn)該功能衫冻。

具體代碼,如下所示:

import random
import time
from threading import Thread
import queue


def producer(name, count, q):
    for i in range(count):
        food = f'{name} 生產(chǎn)第{i}個(gè)包子'
        print(food)
        q.put(food)


def consumer(name, q):
    while True:
        time.sleep(random.randint(1, 3))
        if q.empty():
            break
        print(f'{name} 消費(fèi)了 {q.get()}')


if __name__ == '__main__':
    q = queue.Queue()
    print(q.empty())
    for i in range(1, 4):
        p = Thread(target=producer, args=(f'生產(chǎn)者{i}', 10, q))
        p.start()

    for i in range(1, 6):
        c = Thread(target=consumer, args=(f'消費(fèi)者{i}', q))
        c.start()

生產(chǎn)者消費(fèi)者模式特點(diǎn)

  • 保證生產(chǎn)者不會(huì)在緩沖區(qū)滿的時(shí)候繼續(xù)向緩沖區(qū)放入數(shù)據(jù)谒出,而消費(fèi)者也不會(huì)在緩沖區(qū)空的時(shí)候隅俘,消耗數(shù)據(jù)邻奠。

  • 當(dāng)緩沖區(qū)滿的時(shí)候,生產(chǎn)者會(huì)進(jìn)入休眠狀態(tài)为居,當(dāng)下次消費(fèi)者開(kāi)始消耗緩沖區(qū)數(shù)據(jù)時(shí)碌宴,生產(chǎn)者才會(huì)被喚醒,開(kāi)始往緩沖區(qū)添加數(shù)據(jù)颜骤;當(dāng)緩沖區(qū)空的時(shí)候唧喉,消費(fèi)者會(huì)進(jìn)入休眠狀態(tài)捣卤,直到生產(chǎn)者往緩沖區(qū)添加數(shù)據(jù)時(shí)才會(huì)被喚醒忍抽。

基礎(chǔ)知識(shí)總結(jié)

到這里,我基本上就將本次實(shí)戰(zhàn)需要用到的基礎(chǔ)知識(shí)都教給大家了董朝,相當(dāng)于拋磚引玉鸠项。拋出我這塊磚,引出小伙伴們的玉子姜。本次的基礎(chǔ)知識(shí)主要分為兩大模塊祟绊,第一個(gè)是面向?qū)ο蟮闹R(shí),第二個(gè)則是線程相關(guān)的知識(shí)哥捕,小伙伴們需要盡可能去熟悉牧抽,才能寫(xiě)出更加高效健壯的爬蟲(chóng)demo。

實(shí)戰(zhàn)篇

工具庫(kù)使用

本次爬蟲(chóng)所需要的工具庫(kù)我先列舉出來(lái)

import requests
from lxml import etree
import threading
from queue import Queue
import re

缺少哪些就自行安裝遥赚。

抓取目標(biāo)

本次實(shí)戰(zhàn)所要抓取的網(wǎng)站是斗圖吧扬舒。網(wǎng)址如下:

https://www.doutub.com/

我們需要抓取的內(nèi)容是該網(wǎng)站下的斗圖表情包。

image

瞬間讓你成為斗圖高手凫佛。啥也別說(shuō)了讲坎,干就完事。

網(wǎng)頁(yè)分析

image

定睛一看愧薛,好家伙晨炕,居然有26頁(yè)的表情包,這不起飛毫炉?

首先來(lái)分析一下不同頁(yè)面url的地址變化瓮栗。

# 第一頁(yè)
https://www.doutub.com/img_lists/new/1

# 第二頁(yè)
https://www.doutub.com/img_lists/new/2

# 第三頁(yè)
https://www.doutub.com/img_lists/new/3

看到這種變化的方式之后難道你不先竊喜一下。

頁(yè)面url地址已經(jīng)搞定瞄勾,那接下來(lái)要弄清楚的就是每一張表情包的url地址了遵馆。

image-20210701200206882

這不是很容易就被聰明的你發(fā)現(xiàn)了嗎?這些鏈接我們采用xpath將其提取出來(lái)即可丰榴。

生產(chǎn)者的實(shí)現(xiàn)

首先货邓,我們先創(chuàng)建兩個(gè)隊(duì)列,一個(gè)用于存儲(chǔ)每一頁(yè)的url地址四濒,另一個(gè)便用于存儲(chǔ)圖片鏈接换况。

具體代碼职辨,如下所示:

   # 建立隊(duì)列
    page_queue = Queue()    # 頁(yè)面url
    img_queue = Queue()     # 圖片url
    for page in range(1, 27):
        url = f'https://www.doutub.com/img_lists/new/{page}'
        page_queue.put(url)

通過(guò)上面的代碼,便將每一頁(yè)的url地址放入了page_queue戈二。

接下來(lái)再通過(guò)創(chuàng)建一個(gè)類(lèi)舒裤,將圖片url放入img_queue中另锋。

具體代碼如下所示:

class ImageParse(threading.Thread):
    def __init__(self, page_queue, img_queue):
        super(ImageParse, self).__init__()
        self.page_queue = page_queue
        self.img_queue = img_queue
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36'
        }

    def run(self):
        while True:
            if self.page_queue.empty():
                break
            url = self.page_queue.get()
            self.parse_img(url)

    def parse_img(self, url):
        response = requests.get(url, headers=self.headers).content.decode('utf-8')
        html = etree.HTML(response)
        img_lists = html.xpath('//div[@class="expression-list clearfix"]')
        for img_list in img_lists:
            img_urls = img_list.xpath('./div/a/img/@src')
            img_names = img_list.xpath('./div/a/span/text()')
            for img_url, img_name in zip(img_urls, img_names):
                self.img_queue.put((img_url, img_name))

消費(fèi)者的實(shí)現(xiàn)

其實(shí)消費(fèi)者很簡(jiǎn)單撬统,我們只需要不斷的從img_page中獲取到圖片的url鏈接并不停的進(jìn)行訪問(wèn)即可。直到兩個(gè)隊(duì)列中有一個(gè)隊(duì)列為空即可退出遮怜。

class DownLoad(threading.Thread):
    def __init__(self, page_queue, img_queue):
        super(DownLoad, self).__init__()
        self.page_queue = page_queue
        self.img_queue = img_queue
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36'
        }

    def run(self):
        while True:
            if self.page_queue.empty() and self.img_queue.empty():
                break
            img_url, filename = self.img_queue.get()
            fix = img_url.split('.')[-1]
            name = re.sub(r'[?鲜滩?.伴鳖,。徙硅!!*\\/|]', '', filename)
            # print(fix)
            data = requests.get(img_url, headers=self.headers).content
            print('正在下載' + filename)
            with open('../image/' + name + '.' + fix, 'wb') as f:
                f.write(data)

最后榜聂,再讓創(chuàng)建好的兩個(gè)線程跑起來(lái)

    for x in range(5):
        t1 = ImageParse(page_queue, img_queue)
        t1.start()
        t2 = DownLoad(page_queue, img_queue)
        t2.start()
        t1.join()
        t2.join()

最后結(jié)果

image

一共抓取了1269張圖片。

從今往后誰(shuí)還能比得上你嗓蘑?就這须肆?這不有爬蟲(chóng)就行!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末桩皿,一起剝皮案震驚了整個(gè)濱河市豌汇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌泄隔,老刑警劉巖拒贱,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異梅尤,居然都是意外死亡柜思,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)巷燥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)赡盘,“玉大人,你說(shuō)我怎么就攤上這事缰揪≡上恚” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵钝腺,是天一觀的道長(zhǎng)抛姑。 經(jīng)常有香客問(wèn)我,道長(zhǎng)艳狐,這世上最難降的妖魔是什么定硝? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮毫目,結(jié)果婚禮上蔬啡,老公的妹妹穿的比我還像新娘诲侮。我一直安慰自己,他們只是感情好箱蟆,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布沟绪。 她就那樣靜靜地躺著,像睡著了一般空猜。 火紅的嫁衣襯著肌膚如雪绽慈。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天辈毯,我揣著相機(jī)與錄音坝疼,去河邊找鬼。 笑死漓摩,一個(gè)胖子當(dāng)著我的面吹牛裙士,可吹牛的內(nèi)容都是我干的入客。 我是一名探鬼主播管毙,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼桌硫!你這毒婦竟也來(lái)了夭咬?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤铆隘,失蹤者是張志新(化名)和其女友劉穎卓舵,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體膀钠,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掏湾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肿嘲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片融击。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖雳窟,靈堂內(nèi)的尸體忽然破棺而出尊浪,到底是詐尸還是另有隱情,我是刑警寧澤封救,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布拇涤,位于F島的核電站,受9級(jí)特大地震影響誉结,放射性物質(zhì)發(fā)生泄漏鹅士。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一惩坑、第九天 我趴在偏房一處隱蔽的房頂上張望掉盅。 院中可真熱鬧嘱朽,春花似錦、人聲如沸怔接。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)扼脐。三九已至岸军,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瓦侮,已是汗流浹背艰赞。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肚吏,地道東北人方妖。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像罚攀,于是被迫代替她去往敵國(guó)和親党觅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容