8 Star 22 Fork 5

尚方宝剑奔波霸 / Ratel

加入 Gitee
与超过 800 万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README.md

Ratel开发文档


简介

Ratel基于urllib和selenium实现request方式和模拟浏览器方式。
在模拟浏览器行为上采用两种浏览器:

  1. chrome浏览器,通过chromedriver实现chrome与selenium通信。(chromedriver下载地址:chromedriver,根据chrome版本选择对应的chromedriver)
  2. phantomjs无界面浏览器,通过phantomjsdriver实现phantomjs与selenium通信。(phantomjs下载地址: phantomjs,根据系统选择对应版本)

在两种操作方式上通过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,下载后解压进入项目根目录通过命令:python setup.py install安装或通过pip直接安装,安装命令: pip install -U selenium)

安装方式:

进入Ratel-1.0根目录通过命令:python setup.py install安装


项目结构

输入图片说明

说明 模块 说明
collect 采集方式 request_basic 实现基于urllib的Request方式
-- -- webdriver_basic 实现基于selenium的模拟方式
common 通用模块 dict 通用字典,当前版本仅保存默认UA
main 主入口 do_task 任务执行入口
task 任务 task_basic 任务

运行流程

输入图片说明


快速入门

使用request方式执行任务

  1. 创建Task类(用于定义任务)
# 导入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
  1. 创建Dispose类(用于定义任务的处理结果)
# 导入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 '<RequestDispose> 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 '<SeleniumDispose> result: %s' % self.__result
  1. 创建Execute类(用于执行任务)
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
  1. 创建Main(主程序入口)
# 导入do_task模块
import ratel.main.do_task as do_task

if __name__ == '__main__':
    do_task.do_pool()
  1. 创建*config.xml配置文件(*表示可使用任意前缀)
<!-- 可在任意目录下创建该文件 -->
<config>
    <options>
        <pool_size>10</pool_size>
    </options>
    <tasks>
        <task>
            <task_class>RequestExecute</task_class>
            <task_package>execute.demo_execute</task_package>
        </task>
    </tasks>
</config>
字段 说明
config 配置
options 系统属性设置
pool_size 进程池大小
tasks 任务集合
task 任务
task_class 执行类
task_package 执行类所在包
  1. 运行main.py开始执行程序

使用selenium方式执行任务

使用方法同request方式,只需将*config.xml中task_class改为SeleniumExecute即可

注:Selenium中关于webdriver的具体使用方法请参考: 文档1文档2


模块解析

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的数量.
  当进程池大小小于总任务数量时多于的任务将延迟执行,直至进程池中有空闲时方能执行

  1. do_dict方法通过遍历传入的字典以多进程执行任务,字典中key为class_name,value为pack_name,进程池默认大小为10
  2. 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 超时时间,单位秒
  1. Response类,请求响应
字段 默认值 说明
response_code 响应码
response_content 响应内容
cookie 响应cookie
request_url 请求url
cookie CookieJar对象
  1. 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需要注意转为对应的类型

仓库评论 ( 3 )

你可以在登录后,发表评论

简介

Ratel基于urllib和selenium实现request方式和模拟浏览器方式。 展开 收起
Python
GPL-2.0
取消

发行版

暂无发行版

Ratel

贡献者

全部

近期动态

加载更多
不能加载更多了
Python
1
https://gitee.com/jiaochuanduo/Ratel.git
git@gitee.com:jiaochuanduo/Ratel.git
jiaochuanduo
Ratel
Ratel
master

搜索帮助