記事ディレクトリ
序文
爬虫類はいいもので、最近使っていくので、ちなみに昔のちょっとしたことを送って、ブログを書いてみます〜
コルーチン
まず、スレッドがマルチスレッドではなく、スレッドは基本的にシングルスレッドであることは明らかですが、このスレッドの特徴は、現在のスレッドがIO状態に入ると、CPUが自動的にタスクを切り替えて改善することです。システムの全体的な運用効率。はい、このコルーチンは実際にはオペレーティングシステムのマルチプロセッシングメカニズムと同じです。実装の効果は、マルチスレッドまたはスレッドプーリングを使用する場合と多少似ていますが、コルーチンはより軽量で、基本的にシングルスレッドが前後に切り替わります。
コルーチンはすぐに開始されます
次に、最初にこのコルーチンの効果を理解しましょう。
Pythonでコルーチンを使用するには、つまり非同期で、awaitとasyncの2つのキーワードをマスターする必要があります。もちろん、コルーチン、asyncioをサポートするライブラリもあります。
最初にコードを見てみましょう。
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
一見、マルチスレッドを実装しているように見えるので、コードを変更します。
6秒がないことを見て、これはどのようになりますか?マルチスレッドの場合、2秒である必要があります。したがって、コルーチンはマルチスレッドではありません。これが最初のポイントです
さて、マルチスレッドではないのに、なぜ2秒しかないのですか。
コルーチンは非同期で実行されます
方法について話す前に、これは実際には非常に簡単です
asyncio.sleep(2)
はこれについて特別なことです、はい、特別なポイントは、このスリープはio操作を実行することと同等であるということです、それであなたは私が何を意味するか理解しますか?
このスリープはIO操作です
ここで3つの非同期操作を開始し、すべてのIOが実行のためにシステムに渡されたため、最終的に2秒しか費やしませんでした。
作業過程
さて、私たちは今結果を経験したので、その理由について話す時が来ました。
まず、最初のキーワードasyncは、このメソッドを宣言することです。コードブロックは非同期であり、
awaitの意味を示すのと同じです。これが、2秒の「秘密」である理由です。これにより、変更されたものが時間のかかるIO操作であることが判明すると、オペレーティングシステムにIO操作を実行するように指示し、CPUに他のタスクを切り替えさせます。シングルスレッドプログラムでは、次のことが可能です。複数のタスク。
タスク管理
これらの2つのキーワードを言いましたが、問題は、誰がオペレーティングシステムに通知し、誰が私のために作業を行うかということです。このとき、asyncioを使用する必要があります。
そうです、コードのこの部分です。
もちろん、コルーチンを作成する方法はたくさんありますが、これはクローラーでより多く使用されるため、ここではこれを3つだけ記述します。(これは、Javaのfurtertaskにいくぶん似ています)
aiohttp
非同期クロールの時間です。クロールリソースとは何かをリクエストしてください。これは実際にはIO操作です。したがって、非同期を使用することはできますが、現時点では、リクエストを使用することはできません。
これを使用する必要があります、最初のダウンロード
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)
では、このaiohttpについてはどうでしょうか?言い方は?リクエストに似たメソッドがたくさんあります。たとえば、今のメソッドはrequests.Session()と同じです(非常に似ています)。
非同期保存
そうは言っても、当然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)
最初に、これはファイルブロックを直接書き込むよりも必ずしも優れているわけではなく、一部のサードパーティライブラリはそれをサポートしていないことを説明します。
非同期コールバック
ここで、ファイルを非同期で保存します。問題は、結果を直接取得してから解析したいということです。したがって、非同期コールバックを作成する必要があります。
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)
さて、これは非同期です。パラメータを取得できるので、これが将来のタスクを使用する理由です。Javaでは、これはcalllabelです。
次に、神レベルのツールであるscapyがあります。これは後で更新されます(状況を参照してください。金曜日になります!)