Der Coroutine-Crawler des kleinen Python-Crawlers ist schnell gestartet

Vorwort

Reptilien sind eine gute Sache, und ich werde sie in letzter Zeit verwenden, also werde ich übrigens die kleinen Dinge versenden, die ich früher gemacht habe, und ich werde ein paar Blogs schreiben~

Coroutine

Zunächst einmal ist klar, dass der Thread nicht multithreaded ist und der Thread im Wesentlichen ein einzelner Thread ist, aber das Merkmal dieses Threads besteht darin, dass die CPU automatisch Aufgaben wechselt, um sie zu verbessern, wenn der aktuelle Thread in den IO-Zustand eintritt die Gesamtbetriebseffizienz des Systems. Ja, diese Coroutine ist eigentlich die gleiche wie der Multiprocessing-Mechanismus des Betriebssystems. Der Effekt der Implementierung ähnelt in gewisser Weise der Verwendung von Multi-Threading oder Thread-Pooling, aber die Coroutine ist leichter, im Wesentlichen ein einzelner Thread, der hin und her wechselt.

Coroutinen beginnen schnell

Dann lassen Sie uns zuerst die Wirkung dieser Coroutine verstehen.
Um Coroutinen in Python zu verwenden, also asynchron, müssen wir zwei Schlüsselwörter beherrschen, await und async. Natürlich gibt es auch eine Bibliothek, die Coroutinen unterstützt, asyncio.
Schauen wir uns zuerst den Code an.

import asyncio
import time
# 协程函数
async def do_some_work(x):
    print('doing: ', x)
    await asyncio.sleep(2)
    return 'done {}'.format(x)

# 协程对象
xs = [1,2,3]
# 将协程转成task,并组成list
tasks = []
start  = time.time()
for x in xs:
    c = do_some_work(x)
    tasks.append(asyncio.ensure_future(c))

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

print(time.time()-start

Bildbeschreibung hier einfügen

Auf den ersten Blick scheinen wir Multi-Threading implementiert zu haben, also werde ich den Code ändern.
Bildbeschreibung hier einfügen
Bildbeschreibung hier einfügen
Da es keine 6 Sekunden gibt, wie kann das sein?Wenn es Multithreading ist, müssen es 2 Sekunden sein. Coroutinen sind also nicht multithreaded, das ist der erste Punkt

Nun, da es nicht multithreaded ist, warum sind es nur zwei Sekunden.

Coroutinen werden asynchron ausgeführt

Das ist eigentlich ganz einfach, bevor wir über eine Methode sprechen müssen

asyncio.sleep(2)
ist das Besondere daran, ja, das Besondere ist, dass dieser Ruhezustand der Ausführung einer io-Operation entspricht, Sie verstehen also, was ich meine:
Dieser Ruhezustand ist eine IO-Operation

Wir haben hier 3 asynchrone Operationen gestartet, und alle IOs wurden zur Ausführung an das System übergeben, sodass wir am Ende nur 2 Sekunden gebraucht haben.

Arbeitsprozess

Nun, wir haben jetzt das Ergebnis erlebt, also ist es an der Zeit, darüber zu sprechen, warum.
Zunächst einmal ist das erste Schlüsselwort async, diese Methode zu deklarieren. Der Codeblock ist eine asynchrone Sache, was gleichbedeutend mit der Angabe ist,
was await bedeutet. Deshalb sind wir das „Geheimnis“ von zwei Sekunden. Wenn dieses Ding feststellt, dass es sich bei dem von ihm modifizierten Ding um eine zeitaufwändige IO-Operation handelt, weist es das Betriebssystem an, die IO-Operation durchzuführen, und lässt die CPU andere Aufgaben wechseln.In einem Singlethread-Programm kann dies der Fall sein mehrere Aufgaben. .

Aufgabenmanagement

Wir haben diese beiden Schlüsselwörter gesagt, dann ist die Frage, wer das dem Betriebssystem mitteilt und wer die Arbeit für mich erledigt. Zu diesem Zeitpunkt müssen Sie asyncio verwenden.
Bildbeschreibung hier einfügen

Das ist richtig, dieser Teil des Codes.

Natürlich gibt es viele Möglichkeiten, Coroutinen zu erstellen, aber das wird eher in Crawlern verwendet, also schreibe ich hier nur diese eine, eigentlich drei. (Dies ist etwas ähnlich wie furtertask in Java)

aiohttp

Jetzt ist es an der Zeit für unser asynchrones Crawling. Fordern Sie eins an, was die Crawling-Ressource ist, dies ist eigentlich eine IO-Operation. Wir können also async verwenden, aber zu diesem Zeitpunkt können wir keine Anfragen mehr verwenden.

Sie müssen dies verwenden, zuerst herunterladen

pip install aiohttp
import asyncio
import time
import aiohttp

#随便访问三次bing主页吧
urls = ["https://cn.bing.com/?FORM=Z9FD1",
        "https://cn.bing.com/?FORM=Z9FD1",
        "https://cn.bing.com/?FORM=Z9FD1"]

async def get_page(url):
    print("开始爬取网站", url)
    #异步块,在执行异步方法的时候加上await才能切换,不然就是串行咯
    async with aiohttp.ClientSession() as session:
        async with await session.get(url) as resp:
            page = await resp.text()
    print("爬取完成->",url)
    return page

tasks = []
start  = time.time()
for url in urls:
    c = get_page(url)
    tasks.append(asyncio.ensure_future(c))

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

print(time.time()-start)

Was ist also mit dieser aiohttp-Sache?Wie soll ich es sagen?Es gibt viele Methoden darin, die Requests ähneln.Zum Beispiel ist die Methode gerade jetzt die gleiche wie reviews.Session() (sehr ähnlich)

Asynchrones Speichern

Allerdings gibt es natürlich auch Aiofiles.

import asyncio
import time
import aiohttp
import aiofiles
#随便访问三次bing主页吧
urls = ["https://cn.bing.com/?FORM=Z9FD1",
        "https://cn.bing.com/?FORM=Z9FD1",
        "https://cn.bing.com/?FORM=Z9FD1"]

async def get_page(url):
    print("开始爬取网站", url)
    #异步块,在执行异步方法的时候加上await才能切换,不然就是串行咯
    async with aiohttp.ClientSession() as session:
        async with await session.get(url) as resp:
            page = await resp.text()
    print("爬取完成->",url)
    # async with aiofiles.open("a.html",'w',encoding='utf-8') as f:
    #     await f.write(page)
    #     await f.flush()
    #     await f.close()
    with open("a.html",'w',encoding='utf-8') as f:
        f.write(page)
        f.flush()
        f.close()
    return page

tasks = []
start  = time.time()
for url in urls:
    c = get_page(url)
    tasks.append(asyncio.ensure_future(c))

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

print(time.time()-start)

Lassen Sie mich zunächst erklären, dass dies nicht unbedingt besser ist, als Dateiblöcke direkt zu schreiben, und einige Bibliotheken von Drittanbietern dies nicht unterstützen!

Asynchroner Rückruf

Wir speichern die Datei jetzt asynchron.Das Problem ist, dass ich das Ergebnis direkt bekommen und dann parsen möchte. Also müssen wir einen asynchronen Rückruf machen.
Bildbeschreibung hier einfügen
Bildbeschreibung hier einfügen

import asyncio
import time
import aiohttp
import aiofiles
#随便访问三次bing主页吧
urls = ["https://cn.bing.com/?FORM=Z9FD1",
        "https://cn.bing.com/?FORM=Z9FD1",
        "https://cn.bing.com/?FORM=Z9FD1"]

async def get_page(url):
    print("开始爬取网站", url)
    #异步块,在执行异步方法的时候加上await才能切换,不然就是串行咯
    async with aiohttp.ClientSession() as session:
        async with await session.get(url) as resp:
            page = await resp.text()
    print("爬取完成->",url)
    return page

def parse(task):
    page = task.result() #得到返回结果
    print(len(page))

tasks = []
start  = time.time()
for url in urls:
    c = get_page(url)
    task = asyncio.ensure_future(c)
    task.add_done_callback(parse)
    tasks.append(task)

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

print(time.time()-start)

Nun, das ist eine asynchrone Sache. Deshalb verwende ich die Future-Task, weil ich die Parameter bekommen kann. In Java ist es das Calllabel.
Als nächstes gibt es ein Werkzeug auf Gottebene, scapy, das später aktualisiert wird (siehe die Situation, es wird Freitag sein!)

Ich denke du magst

Origin blog.csdn.net/FUTEROX/article/details/123284841
Empfohlen
Rangfolge