<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          天下武功,唯快不破!如何用Python發(fā)送 10 萬個(gè) http 請(qǐng)求?

          共 4475字,需瀏覽 9分鐘

           ·

          2021-10-03 16:19

          假如有一個(gè)文件,里面有 10 萬個(gè) url,需要對(duì)每個(gè) url 發(fā)送 http 請(qǐng)求,并打印請(qǐng)求結(jié)果的狀態(tài)碼,如何編寫代碼盡可能快的完成這些任務(wù)呢?

          Python 并發(fā)編程有很多方法,多線程的標(biāo)準(zhǔn)庫 threading,concurrency,協(xié)程 asyncio,當(dāng)然還有 grequests 這種異步庫,每一個(gè)都可以實(shí)現(xiàn)上述需求,下面一一用代碼實(shí)現(xiàn)一下,本文的代碼可以直接運(yùn)行,給你以后的并發(fā)編程作為參考:

          隊(duì)列+多線程

          定義一個(gè)大小為 400 的隊(duì)列,然后開啟 200 個(gè)線程,每個(gè)線程都是不斷的從隊(duì)列中獲取 url 并訪問。

          主線程讀取文件中的 url 放入隊(duì)列中,然后等待隊(duì)列中所有的元素都被接收和處理完畢。代碼如下:

          from?threading?import?Thread
          import?sys
          from?queue?import?Queue
          import?requests

          concurrent?=?200


          def?doWork():
          ????while?True:
          ????????url?=?q.get()
          ????????status,?url?=?getStatus(url)
          ????????doSomethingWithResult(status,?url)
          ????????q.task_done()


          def?getStatus(ourl):
          ????try:
          ????????res?=?requests.get(ourl)
          ????????return?res.status_code,?ourl
          ????except:
          ????????return?"error",?ourl


          def?doSomethingWithResult(status,?url):
          ????print(status,?url)


          q?=?Queue(concurrent?*?2)
          for?i?in?range(concurrent):
          ????t?=?Thread(target=doWork)
          ????t.daemon?=?True
          ????t.start()

          try:
          ????for?url?in?open("urllist.txt"):
          ????????q.put(url.strip())
          ????q.join()
          except?KeyboardInterrupt:
          ????sys.exit(1)

          運(yùn)行結(jié)果如下:有沒有 get 到新技能?

          線程池

          如果你使用線程池,推薦使用更高級(jí)的 concurrent.futures 庫:

          import?concurrent.futures
          import?requests

          out?=?[]
          CONNECTIONS?=?100
          TIMEOUT?=?5

          urls?=?[]
          with?open("urllist.txt")?as?reader:
          ????for?url?in?reader:
          ????????urls.append(url.strip())

          def?load_url(url,?timeout):
          ????ans?=?requests.get(url,?timeout=timeout)
          ????return?ans.status_code

          with?concurrent.futures.ThreadPoolExecutor(max_workers=CONNECTIONS)?as?executor:
          ????future_to_url?=?(executor.submit(load_url,?url,?TIMEOUT)?for?url?in?urls)
          ????for?future?in?concurrent.futures.as_completed(future_to_url):
          ????????try:
          ????????????data?=?future.result()
          ????????except?Exception?as?exc:
          ????????????data?=?str(type(exc))
          ????????finally:
          ????????????out.append(data)
          ????????????print(data)

          協(xié)程 + aiohttp

          協(xié)程也是并發(fā)非常常用的工具了:

          import?asyncio
          from?aiohttp?import?ClientSession,?ClientConnectorError

          async?def?fetch_html(url:?str,?session:?ClientSession,?**kwargs)?->?tuple:
          ????try:
          ????????resp?=?await?session.request(method="GET",?url=url,?**kwargs)
          ????except?ClientConnectorError:
          ????????return?(url,?404)
          ????return?(url,?resp.status)

          async?def?make_requests(urls:?set,?**kwargs)?->?None:
          ????async?with?ClientSession()?as?session:
          ????????tasks?=?[]
          ????????for?url?in?urls:
          ????????????tasks.append(
          ????????????????fetch_html(url=url,?session=session,?**kwargs)
          ????????????)
          ????????results?=?await?asyncio.gather(*tasks)

          ????for?result?in?results:
          ????????print(f'{result[1]}?-?{str(result[0])}')

          if?__name__?==?"__main__":
          ????import?sys
          ????assert?sys.version_info?>=?(3,?7),?"Script?requires?Python?3.7+."
          ????with?open("urllist.txt")?as?infile:
          ????????urls?=?set(map(str.strip,?infile))
          ????asyncio.run(make_requests(urls=urls))

          grequests[1]

          這是個(gè)第三方庫,目前有 3.8K 個(gè)星,就是 Requests + Gevent[2],讓異步 http 請(qǐng)求變得更加簡(jiǎn)單。Gevent 的本質(zhì)還是協(xié)程。

          使用前:

          pip?install?grequests

          使用起來那是相當(dāng)?shù)暮?jiǎn)單:

          import?grequests

          urls?=?[]
          with?open("urllist.txt")?as?reader:
          ????for?url?in?reader:
          ????????urls.append(url.strip())

          rs?=?(grequests.get(u)?for?u?in?urls)

          for?result?in?grequests.map(rs):
          ????print(result.status_code,?result.url)

          注意 grequests.map(rs) 是并發(fā)執(zhí)行的。運(yùn)行結(jié)果如下:也可以加入異常處理:

          >>>?def?exception_handler(request,?exception):
          ...????print("Request?failed")

          >>>?reqs?=?[
          ...????grequests.get('http://httpbin.org/delay/1',?timeout=0.001),
          ...????grequests.get('http://fakedomain/'),
          ...????grequests.get('http://httpbin.org/status/500')]
          >>>?grequests.map(reqs,?exception_handler=exception_handler)
          Request?failed
          Request?failed
          [None,?None,?500]>]

          最后的話

          今天分享了并發(fā) http 請(qǐng)求的幾種實(shí)現(xiàn)方式,有人說異步(協(xié)程)性能比多線程好,其實(shí)要分場(chǎng)景看的,沒有一種方法適用所有的場(chǎng)景,筆者就曾做過一個(gè)實(shí)驗(yàn),也是請(qǐng)求 url,當(dāng)并發(fā)數(shù)量超過 500 時(shí),協(xié)程明顯變慢。

          參考資料

          [1]grequests: https://github.com/spyoungtech/grequests

          [2]Gevent: http://www.gevent.org/






          推薦閱讀:

          入門:?最全的零基礎(chǔ)學(xué)Python的問題? |?零基礎(chǔ)學(xué)了8個(gè)月的Python??|?實(shí)戰(zhàn)項(xiàng)目?|學(xué)Python就是這條捷徑


          量化:?定投基金到底能賺多少錢?? |?我用Python對(duì)去年800只基金的數(shù)據(jù)分析??


          干貨:爬取豆瓣短評(píng),電影《后來的我們》?|?38年NBA最佳球員分析?|? ?從萬眾期待到口碑撲街!唐探3令人失望? |?笑看新倚天屠龍記?|?燈謎答題王?|用Python做個(gè)海量小姐姐素描圖?|碟中諜這么火,我用機(jī)器學(xué)習(xí)做個(gè)迷你推薦系統(tǒng)電影


          趣味:彈球游戲? |?九宮格? |?漂亮的花?|?兩百行Python《天天酷跑》游戲!


          AI:?會(huì)做詩的機(jī)器人?|?給圖片上色?|?預(yù)測(cè)收入?|?碟中諜這么火,我用機(jī)器學(xué)習(xí)做個(gè)迷你推薦系統(tǒng)電影


          小工具:?Pdf轉(zhuǎn)Word,輕松搞定表格和水印!?|?一鍵把html網(wǎng)頁保存為pdf!|??再見PDF提取收費(fèi)!?|?用90行代碼打造最強(qiáng)PDF轉(zhuǎn)換器,word、PPT、excel、markdown、html一鍵轉(zhuǎn)換?|?制作一款釘釘?shù)蛢r(jià)機(jī)票提示器!?|60行代碼做了一個(gè)語音壁紙切換器天天看小姐姐!


          年度爆款文案


          點(diǎn)閱讀原文,領(lǐng)AI全套資料!

          瀏覽 19
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一区=区黄色 | 69AV网| 亚洲AV手机在线免费观看 | 日韩色网站 | 成人无码精品 |