【问题标题】:Asyncio google search in PythonPython中的异步谷歌搜索
【发布时间】:2021-12-17 16:07:49
【问题描述】:

鉴于我仍在学习一般的异步编程,如果这个问题太基本了,我深表歉意。 我想对使用 Python 的公司列表进行 Google 搜索。因为列表中有超过 20,000 家公司,我想异步执行这些操作。我尝试使用 Python 中的 asyncio 库执行此操作,但我无法让它工作,它仍然同步运行超过 4 小时。 如何使下面的代码异步运行?

当我运行这个时:

from googlesearch import search
import asyncio

companies = [
  'Apple',
  'Google',
  'Tesla'
]

async def gsearch(company):
  return search(company, num=3, stop=3)

async def make_gsearch(company):
  print(f"Searching {company}")
  search_res = await gsearch(company)
  print(f"Done with {company}")
  return list(search_res)

async def run_search():
  return await asyncio.gather(*[make_gsearch(company) for company in companies])
  
asyncio.run(run_search())

我得到这个输出:

Searching Apple
Done with Apple
Searching Google
Done with Google
Searching Tesla
Done with Tesla

但我想让它在等待其他搜索结果返回时开始每次搜索。这将产生类似:

Searching Apple
Searching Google
Searching Tesla
Done with Apple
Done with Google
Done with Tesla

任何帮助表示赞赏, 谢谢

【问题讨论】:

  • 你考虑过多线程吗?它更容易(恕我直言)并且完全适合您的需求
  • 问题是sesrch仍然是一个阻塞调用。你要么需要切换到 asyncio 感知的东西,要么按照上面的建议使用 concurrent.futures。
  • 感谢您的 cmets!我有2万家公司,启动2万线程可以吗?

标签: python python-asyncio


【解决方案1】:

我在评论部分建议使用多线程。以下是您如何处理此问题的示例:

from googlesearch import search
from concurrent.futures import ThreadPoolExecutor

companies = [
  'Apple',
  'Google',
  'Tesla'
]

def gsearch(company):
    return search(company, num_results=3)

def main():
    with ThreadPoolExecutor() as executor:
        for future in [executor.submit(gsearch, company) for company in companies]:
            print(future.result())

if __name__ == '__main__':
    main()

输出:

['https://www.apple.com/uk/', 'https://www.apple.com/uk/', '/search?q=Apple&num=4&hl=en&tbm=isch&source=iu&ictx=1&fir=-TtEc9M5pE7LPM%252CobY4_sHHUHwJ8M%252C%252Fm%252F0k8z&vet=1&usg=AI4_-kQBxGosm-inv0sd7rMvgQiQEXKyzw&sa=X&ved=2ahUKEwjJ1cC9oev0AhWT8OAKHYa4Bc4Q_B16BAgVEAI#imgrc=-TtEc9M5pE7LPM']
['https://www.google.co.uk/', 'https://www.google.co.uk/', 'https://twitter.com/Google?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor', '/search?q=Google&num=4&hl=en&tbm=isch&source=iu&ictx=1&fir=mM5eejaz-bUIsM%252C0UCf55-GTy6fDM%252C%252Fm%252F045c7b&vet=1&usg=AI4_-kS3fhB6I4-4YGkbI-0POxk60cjoEw&sa=X&ved=2ahUKEwjk1MC9oev0AhWKsBQKHcNXATsQ_B16BAgnEAI#imgrc=mM5eejaz-bUIsM']
['https://www.tesla.com/en_gb', 'https://www.tesla.com/en_gb', '/search?q=Tesla&num=4&hl=en&tbm=isch&source=iu&ictx=1&fir=TJ5IFimoIu4OzM%252Cahl5uU9rAQNcyM%252C%252Fm%252F0dr90d&vet=1&usg=AI4_-kS3EuOF372E5qoJG2eO01XrJehNdA&sa=X&ved=2ahUKEwip3sC9oev0AhWG2hQKHavHCzwQ_B16BAgmEAI#imgrc=TJ5IFimoIu4OzM']

更新:

我将公司的数量增加到 20 家(所有独特且真实的公司)。执行(包括打印)的总持续时间小于 2 秒

【讨论】:

  • 感谢您的解决方案。我有点担心启动 20000 个线程来遍历完整列表,不确定这是否安全,你会推荐吗?另外,我需要将所有结果存储在某种列表中,附加到最终列表时是否需要为线程使用锁?再次感谢!
  • 您不太可能拥有那么多并发线程。这就是线程池的重点——只有您的系统可以合理处理的数量。这是完全安全的。当您使用线程(而不是子进程)时,请记住 Python 字典和列表是线程安全的。这意味着每个线程都可以可靠地将数据添加到某个全局对象
  • 当然,您始终可以通过将 max_workers 指定给 ThreadPoolExecutor 构造函数来应用限制
  • 更新:如果您要尝试使用 googlesearch 搜索 20,000 家公司,那么您极有可能开始收到 HTTP 429 错误。 Google 不会再爱你了 ;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-25
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
  • 2016-11-22
  • 1970-01-01
  • 2016-10-11
相关资源
最近更新 更多