# Ratel **Repository Path**: hwsyy/Ratel ## Basic Information - **Project Name**: Ratel - **Description**: Ratel基于urllib和selenium实现request方式和模拟浏览器方式。 - **Primary Language**: Python - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 5 - **Created**: 2017-11-19 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Ratel开发文档 --- # 简介 Ratel基于urllib和selenium实现request方式和模拟浏览器方式。 在模拟浏览器行为上采用两种浏览器: 1. chrome浏览器,通过chromedriver实现chrome与selenium通信。(chromedriver下载地址:[chromedriver](https://npm.taobao.org/mirrors/chromedriver),根据chrome版本选择对应的chromedriver) 2. phantomjs无界面浏览器,通过phantomjsdriver实现phantomjs与selenium通信。(phantomjs下载地址: [phantomjs](http://phantomjs.org/download.html),根据系统选择对应版本) 在两种操作方式上通过cookie传递可实现快速切换,例如:当进行论坛发布时,通常需要登录账号后才能发布,在模拟登录请求时个别参数难以分析,这时可以采用selenium进行模拟浏览器登录,就像人操作浏览器一样输入账号密码点击登录即可登录,然后将登录成功的cookie传递给request方法即可通过request方式进行发布操作。 在浏览器选择上推荐首选phantomjs,当个别站点页面phantomjs无法渲染时选择chrome浏览器,例如:QQ群管理页面只能通过真实的浏览器渲染页面。 在使用chrome浏览器时系统只能是Windows或Ubuntu系统。chrome现已不支持CentOS系统。若还需Java进行辅助操作只能选择Ubuntu系统或尝试使用除阿里云之外的云机器,因为在阿里云的Windows系统中Thread.sleep命令延时异常不精准可能会卡死。 --- # 安装 ### 开发环境: Ratel适用于Python3以上版本 ### 扩展依赖: selenium3.7.0(下载地址: [Selenium3.7.0](https://pypi.python.org/pypi/selenium/3.7.0),下载后解压进入项目根目录通过命令:python setup.py install安装或通过pip直接安装,安装命令: pip install -U selenium) ### 安装方式: 进入Ratel-1.0根目录通过命令:python setup.py install安装 --- # 项目结构 ![输入图片说明](https://gitee.com/uploads/images/2017/1117/190040_00af2fd8_1073396.png "image001.png") |包|说明|模块|说明| |:-:|:-:|:-:|:-:| |collect|采集方式|request_basic|实现基于urllib的Request方式| |--|--|webdriver_basic|实现基于selenium的模拟方式| |common|通用模块|dict|通用字典,当前版本仅保存默认UA| |main|主入口|do_task|任务执行入口| |task|任务|task_basic|任务| --- # 运行流程 ![输入图片说明](https://gitee.com/uploads/images/2017/1117/190107_6af84a04_1073396.png "image002.png") --- # 快速入门 ### 使用request方式执行任务 1) 创建Task类(用于定义任务) ```python # 导入Task基类 from ratel.task.task_basic import Task class RequestTask(Task): def __init__(self): """ request方式的任务 """ self.__url = None self.__result = None @property def get_url(self): return self.__url def set_url(self, url): self.__url = url @property def get_result(self): return self.__result def set_result(self, result): self.__result = result class SeleniumTask(Task): def __init__(self): """ selenium方式的任务 """ self.__url = None self.__result = None @property def get_url(self): return self.__url def set_url(self, url): self.__url = url @property def get_result(self): return self.__result def set_result(self, result): self.__result = result ``` 2) 创建Dispose类(用于定义任务的处理结果) ```python # 导入Dispose基类 from ratel.task.task_basic import Dispose class RequestDispose(Dispose): def __init__(self): self.__result = None @property def get_result(self): return self.__result def set_result(self, result): self.__result = result def __str__(self): return ' result: %s' % self.__result class SeleniumDispose(Dispose): def __init__(self): self.__result = None @property def get_result(self): return self.__result def set_result(self, result): self.__result = result def __str__(self): return ' result: %s' % self.__result ``` 3) 创建Execute类(用于执行任务) ```python from ratel.task.task_basic import Execute from task.demo_task import RequestTask, SeleniumTask from dispose.demo_dispose import RequestDispose, SeleniumDispose from ratel.collect.request_basic import Url, request_url from ratel.collect.webdriver_basic import Driver import time import threading class RequestExecute(Execute): def __init__(self): Execute.__init__(self) def get_task(self): """ 模拟取任务,任务可使用队列 :return: """ while True: # 模拟创建一条任务 task = RequestTask() task.set_url(Url(url='http://www.baidu.com', method='GET')) # 将任务放入至队列 self.put_task(task) time.sleep(10) def do_task(self): """ 模拟执行任务 :return: """ # 使用线程取任务, 可不使用 threading.Thread(target=self.get_task, name='get_task', daemon=True).start() # 使用线程上报任务, 可不使用 threading.Thread(target=self.up_task, name='up_task', daemon=True).start() while True: # 判断队列是否为空 if not self.task_empty: try: # 从队列中取出任务 task = self.poll_task # 通知队列任务以取出 self.task_done() # 执行任务 resp = request_url(url=task.get_url) # 处理任务结果 task.set_result(self.dispose(resp)) self.put_success(task) except Exception as e: print(e) time.sleep(2) def dispose(self, result): """ 模拟处理任务 :param result: :return: """ # 将任务的处理结果放入上报队列 request_dispose = RequestDispose() request_dispose.set_result(result) return request_dispose def up_task(self): """ 模拟上报任务 :return: """ while True: # 判断队列是否为空 if not self.success_empty: # 取出任务 task = self.poll_success self.success_done() # 模拟上报 print(task.get_result) time.sleep(2) def end(self): """ 任务结束的处理,例如释放资源等 :return: """ pass class SeleniumExecute(Execute): def __init__(self): Execute.__init__(self) def get_task(self): while True: task = SeleniumTask() task.set_url("http://www.baidu.com") self.put_task(task) time.sleep(10) def do_task(self): # 使用线程取任务, 可不使用 threading.Thread(target=self.get_task, name='get_task', daemon=True).start() # 使用线程上报任务, 可不使用 threading.Thread(target=self.up_task, name='up_task', daemon=True).start() while True: if not self.task_empty: try: task = self.poll_task self.task_done() # 创建chromeDriver driver_impl = Driver(driver_type='chrome', executable_path='/Users/xw/Documents/Tools/chromedriver') driver = driver_impl.get_driver # 打开浏览器并跳转到指定URL driver.get(task.get_url) # 等待页面加载 """ 等待有3种方式 1).time.sleep(),最简单的方式但过于死板,不管页面是否加载完毕都要等待 2).driver.implicitly_wait(),较sleep稍好,但仍有局限性当超过等待时间页面未加载完毕会抛出异常 3).selenium.webdriver.support.wait模块中的WebDriverWait,可根据条件灵活的设置等待时间. 调用该类的until或until_not方法让程序每隔n秒去判断一下条件,看是否满足,如不满足,继续等待直至超时. 超时会抛出TimeoutException异常 """ time.sleep(5) result = driver.page_source driver.close() task.set_result(self.dispose(result)) self.put_success(task) except Exception as e: print(e) time.sleep(2) def dispose(self, result): selenium = SeleniumDispose() selenium.set_result(result) return selenium def up_task(self): """ 模拟上报任务 :return: """ while True: # 判断队列是否为空 if not self.success_empty: # 取出任务 task = self.poll_success self.success_done() # 模拟上报 print(task.get_result) time.sleep(2) def end(self): pass ``` 4) 创建Main(主程序入口) ```python # 导入do_task模块 import ratel.main.do_task as do_task if __name__ == '__main__': do_task.do_pool() ``` 5) 创建*config.xml配置文件(*表示可使用任意前缀) ```xml 10 RequestExecute execute.demo_execute ``` |字段|说明| |:-:|:-:| |config|配置| |options|系统属性设置| |pool_size|进程池大小| |tasks|任务集合| |task|任务| |task_class|执行类| |task_package|执行类所在包| 6) 运行main.py开始执行程序 ### 使用selenium方式执行任务 使用方法同request方式,只需将*config.xml中task_class改为SeleniumExecute即可 > 注:Selenium中关于webdriver的具体使用方法请参考: [文档1](http://docs.seleniumhq.org/docs/03_webdriver.jsp)或[文档2](http://www.webdriver.org/nav1/) --- # 模块解析 ### task_basic模块(提供任务支持) 1) Task类,作为任务基类.在开发中每一个任务类都应继承该类 2) Dispose类,作为处理结果类,在开发中每一个结果类都应继承该类 3) Execute类,作为任务执行类,在开发中每一个执行类都必须继承该类,否则不能执行任务 Execute类中提供了两个队列,分别是任务队列和上报队列.该队列在__init__方法中初始化, 因此每一个继承该类的执行类都必须在__init__方法中调用基类的__init__方法,除非不使用队列存取任务. 在使用队列时,通过*_empty方法判断队列是否为空,当队列为空时获取任务会抛出异常, 从队列中取完任务后应调用task_done方法通知队列删除当前任务. Execute类中还提供了五个方法: |方法|参数|说明| |:-:|:-:|:-:| |get_task|无|获取任务.任务可使用队列存放.推荐使用多线程调用该方法| |do_task|无|执行任务.可在该方法内通过线程调用get_task和up_task实现异步获取上报任务| |up_task|无|上报任务.任务可使用队列存放,推荐使用多线程调用该方法| |dispose|result|处理任务结果| |end|无|任务结束后的处理,例如释放资源,持久化数据等| ### do_task模块(提供任务调度) 1) do_pool方法通过读取config.xml以多进程执行任务.进程池默认大小为10可通过修改config.xml中的pool_size设置进程池大小 > 注: 推荐进程池大小大于config.xml中task的数量. >   当进程池大小小于总任务数量时多于的任务将延迟执行,直至进程池中有空闲时方能执行 2) do_dict方法通过遍历传入的字典以多进程执行任务,字典中key为class_name,value为pack_name,进程池默认大小为10 3) do方法以单进程执行单一任务 ### dict模块(提供默认设置) header_default默认请求头,提供Chrome,Firefox,IE的请求头 ### request_basic模块(提供基于Request方式执行任务) 1) Url类,创建请求 |字段|默认值|说明| |:-:|:-:|:-:| |url|无|请求地址,必传.地址中必须包含http://或https://| |method|GET|请求方式,支持GET和POST| |header|Chrome_UA|请求头| |data|无|请求参数,dict类型,此参数仅对POST方式有效| |cookie|无|CookieJar对象| |proxy|无|代理ip| |retry_num|3|异常重试次数| |time_out|30|超时时间,单位秒| 2) Response类,请求响应 |字段|默认值|说明| |:-:|:-:|:-:| |response_code|无|响应码| |response_content|无|响应内容| |cookie|无|响应cookie| |request_url|无|请求url| |cookie|无|CookieJar对象| 3) request_url方法负责发送请求,参数为url(Url类对象), encodeing(请求参数编码,默认utf-8) ### webdriver_basic模块(提供基于Selenium方式执行任务) Driver类,创建webdriver |字段|默认值|说明| |:-:|:-:|:-:| |driver_type|无|webdriver类型,仅支持chrome和phantomjs,必传| |executable_path|无|驱动路径| |headers|无|请求头,chrome仅支持设置UA| |cookies|无|cookie,dict类型| |proxy|无|代理ip| |loadimgs|True|加载图片,推荐phantomjs禁止加载图片以加快请求速度| > 注:如需使用Firefox, IE 或其他浏览器请参考相关文档,如需在两种方式之间互传cookie需要注意转为对应的类型