1. import asyncio
  2. import aiohttp
  3. import async_timeout
  4. from lxml import html
  5. from timeit import default_timer as timer
  6.  
  7. from db import DBData
  8.  
  9. class Crawler:
  10. def __init__(self, **kwargs):
  11. self.domains = kwargs["domains"]
  12. self.max_depth = kwargs["max_depth"]
  13. self.max_retries = 3
  14. self.max_workers = 10
  15. self.Q = asyncio.Queue()
  16. self.db_Q = asyncio.Queue()
  17. self.cache = set()
  18. self.count = 0
  19. self.loop = asyncio.get_event_loop()
  20. self.db_data = DBData()
  21.  
  22. # Clear
  23. self.db_data.clear_crawler()
  24.  
  25. async def get(self, url, timeout):
  26. with async_timeout.timeout(timeout):
  27. async with self.session.get(url) as response:
  28. return await response.text()
  29.  
  30. async def extract_urls(self, url, timeout=10):
  31. tree = html.fromstring(await self.get(url, timeout))
  32. # Search only in domains
  33. return {p for p in tree.xpath("//a/@href")}
  34. # if any(domain in p for domain in self.domains)}
  35.  
  36. async def worker(self):
  37. while True:
  38. url, depth, retries = await self.Q.get()
  39. if url in self.cache:
  40. self.db_Q.put_nowait(url)
  41. self.Q.task_done()
  42. continue
  43. try:
  44. new_urls = await self.extract_urls(url)
  45. except Exception as e:
  46. if retries <= self.max_retries:
  47. self.Q.put_nowait((url, depth, retries + 1))
  48. else:
  49. print("Error in %s: %s" % (url, repr(e)))
  50. else:
  51. self.cache.add(url)
  52. self.count += 1
  53. self.db_Q.put_nowait(url)
  54. print("Depth: %s Retry: %s Visited: %s" % (depth, retries, url))
  55. if depth+1 <= self.max_depth:
  56. for x in new_urls:
  57. self.Q.put_nowait((x, depth + 1, retries))
  58. self.Q.task_done()
  59.  
  60. async def run(self):
  61. async with aiohttp.ClientSession(loop=self.loop) as session:
  62. self.session = session
  63. workers = [self.worker() for _ in range(self.max_workers)]
  64. workers += [self.write_to_db() for _ in range(self.max_workers)]
  65. tasks = [self.loop.create_task(x) for x in workers]
  66. await asyncio.sleep(5)
  67. await self.Q.join()
  68. await self.db_Q.join()
  69. for task in tasks:
  70. task.cancel()
  71.  
  72. def start(self):
  73. for domain in self.domains:
  74. print("Crawling %s start..." % domain)
  75.  
  76. self.Q.put_nowait((domain, 0, 0))
  77. start_time = timer()
  78. self.loop.run_until_complete(asyncio.gather(self.run()))
  79. self.loop.close()
  80. runtime = timer() - start_time
  81.  
  82. print("Crawling %s end. Exec time: %s. Requests: %s" % (
  83. domain, runtime, self.count))
  84.  
  85. async def write_to_db(self):
  86. while True:
  87. address = await self.db_Q.get()
  88. if await self.db_data.check_url(address) is None:
  89. self.db_data.add_url(address)
  90. print("Write to DB: %s" % address)
  91. self.db_Q.task_done()
  92.  
  93. if __name__ == "__main__":
  94. options = {
  95. "domains": ["https://www.yahoo.com/news/"],
  96. "max_depth": 1
  97. }
  98. c = Crawler(**options)
  99. c.start()

aiohttp爬虫的模板,类的形式的更多相关文章

  1. C++模板类的使用

    1.定义模板类 通过类似于下面的语法可以定义一个模板类: template<typename T> class Job : public virtual RefBase { public: ...

  2. C++:类模板与模板类

    6.3 类模板和模板类 所谓类模板,实际上是建立一个通用类,其数据成员.成员函数的返回值类型和形参类型不具体指定,用一个虚拟的类型来代表.使用类模板定义对象时,系统会实参的类型来取代类模板中虚拟类型从 ...

  3. C++ 模板类解析

    具体模板类作用这边就不细说了,下面主要是描述下模板类的使用方法以及注意的一些东西. #include <iostream> using namespace std; template &l ...

  4. 使用模板类导致error LNK2019: 无法解析的外部符号

    原地址 1.定义模板类: template<class T> class Stack {....}; 2.定义模板成员函数: 每个函数头都要以相同的模板声明打头,并将类限定符改成:类名&l ...

  5. 开涛spring3(7.2) - 对JDBC的支持 之 7.2 JDBC模板类

    7.2  JDBC模板类 7.2.1  概述 Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDB ...

  6. 7.2 C++模板类实例化

    参考:http://www.weixueyuan.net/view/6399.html 总结: array < int >表明用int类型来代替模板类中的类参数“T”,编译器会将模板类ar ...

  7. [C++]模板类和模板函数

    参考: C++ 中模板使用详解 C++模板详解 概念 为了避免因重载函数定义不全面而带来的调用错误,引入了模板机制 定义 模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模 ...

  8. (转)JDBC模板类。

    Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDBC模板类是第一种工作模式. JdbcTempl ...

  9. spring3:对JDBC的支持 之 JDBC模板类

    7.2  JDBC模板类 7.2.1  概述 Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDB ...

随机推荐

  1. 配置Sharepoint之后。外网无法访问的问题

    Sharepoint配置完成了,projectserver也已经配置完毕.突然遇到一个情况就是外网访问不了,这可麻烦了,费了半天事访问不了等于0啊.没办法,研究吧.在群里问了大神,终于解决了.现将解决 ...

  2. Windows Server、 Windows 区别

    今天脑补了普通Windows 操作系统与Windows Server区别,感觉清楚了很多. Microsoft WindowsServer,是美国微软公司研制的一套操作体系,它面世于1985年,起先仅 ...

  3. BZOJ 1059 矩阵游戏 二分图匹配

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1059 题目大意: 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏 ...

  4. Gluon 参数读取

    ndarray: save , load from mxnet import nd from mxnet.gluon import nn x = nd.ones(3) # nd.save('x',x) ...

  5. Pymyaql操作数据库

    Pymyaql操作数据库 Python3中专门用于操作Mysql数据库的模块. 一. 导入模块 import pymysql 二. 创建连接 conn=pymysql.connect(host=’12 ...

  6. bootstrap清除浮动问题

    所有的col-样式都是左浮动 <div class="row">    <div class="col-xs-6 col-sm-3">d ...

  7. Appium基础篇(一)——启动emulator

    1. Appium API文档:链接参考 http://appium.io/slate/cn/v/?ruby#appium-介绍. 2. Appium 安装篇:http://www.cnblogs.c ...

  8. vue-scroll 底部无数据时,底部出现大片的空白

    vue-scroll放在vue的项目中,实现下拉刷新的效果,但是发现,不能上拉的bug,上拉了之后,底部出现了一大段的空白,参照GitHub的问题,算是暂时解决了. 不能上拉的原因是:滑动标签里边的内 ...

  9. Springboot中使用ibatis输出日志

    logging.level.org.apache.ibatis=DEBUG logging.level.org.mybatis=DEBUG logging.level.java.sql.Connect ...

  10. php多进程编程实现与优化

    PHP多进程API 创建子进程 @params void @returns int int pcntl_fork(void) 成功时,在父进程执行线程内返回产生的子进程PID,在子进程执行线程内返回0 ...