from pycurl_session.spider import Spider, Schedule, Request, FormRequest
class Test(Spider):
def __init__(self):
self.start_urls = ["https://github.com"]
def parse(self, response):
self.log(response.title)
yield FormRequest.from_response(response, method="GET", formdata={"q": "pycurl"}, callback=self.parse_list)
def parse_list(self, response):
self.log(response.title)
url = response.xpath('//ul[contains(@class, "repo-list")]/li//a/@href').get()
yield Request(url=response.urljoin(url), callback=self.parse_detail)
def parse_detail(self, response):
self.log(response.title)
if __name__ == "__main__":
settings = {}
schedule = Schedule(settings)
schedule.add_spider(Test)
schedule.run()
from pycurl_session.spider.schedule.Schedule(custom_settings={})
Parameters:
- custom_settings - 自定义设置。可配置项参考:
- BOT - 用于标识cookie。默认"Spider"
- USER_AGENT - 默认ua,会被DEFAULT_HEADERS["user-agent"]覆盖。默认"Spider Bot"
- DEFAULT_HEADERS - 默认headers
- ROBOTSTXT_OBEY - 是否遵守robots.txt。默认True
- COOKIES_DEBUG - 是否打印cookie
- COOKIES_STORE_ENABLED - 是否保存cookie到sqlite3文件。默认True
- COOKIES_STORE_DB - cookie保存文件位置。默认为临时目录
- COOKIES_CLEAR - 启动时是否清空对应标识的cookie
- DOWNLOAD_TIMEOUT - 下载超时设置。默认30(second)
- DOWNLOAD_DELAY - 相同域名请求延时。默认0(second)
- REDIRECT_ENABLED - 是否自动跳转请求。默认True
- RETRY_TIMES - 最大重试次数,默认3
- RETRY_HTTP_CODES - 重试状态码。默认[500, 502, 503, 504, 522, 524, 408, 429]
- LOG_ENABLED - 是否记录日志。默认False
- LOG_FILE - 日志文件路径,需要LOG_ENABLED=True
- LOG_ENCODING - 日志编码。默认utf-8
- LOG_FORMAT - 日志格式。默认"%(asctime)s %(levelname)s [%(name)s] %(message)s"
- CONCURRENT_REQUESTS - 同时请求连接数。默认16
- DOWNLOADER_MIDDLEWARES - (list) 下载中间件
- ITEM_PIPELINES - (list) Item管道
- DEPTH_PRIORITY - 是否深度优先。默认是
- SIMULATE_FETCH - 是否模拟fetch请求,自动添加一些header。默认否
add_spider(spider, task_provider=Task, **arg)
Parameters:
- spider(Spider) - Spider类
- task_provider(Task) - Task继承类。用于生成请求
- arg - spider初始化参数
run() 启动调度请求
session - pycurl_session.Session()实例
settings - (dict) 全部设置
logstat - (dict) 数据统计
class pycurl_session.spider.Spider()
start_request()
可选,生成器函数。优先于start_urls。和start_urls只取一个
Return:
- Request
parse(response)
Parameters:
- response(Response) - 响应类
log(msg)
Parameters:
- msg(str) - 日志信息
closed(reason)
Parameters:
- reason(str) - 结束原因
name - (str) 爬虫名称
spider_id - (str) 爬虫标识,由Spider.class.__name__和Spider.name组成
start_urls - (list) 初始链接。默认callback为parse()
_session - (Session) Schedule.session
settings - (dict) Schedule.settings
class pycurl_session.spider.request.Request(url, method="GET", callback=None, meta=None,
body=None, data=None, json=None, headers=None, cookies=None,
dont_filter=False, cb_kwargs=None)
Parameters:
- url(str) - 请求链接
- method(str) - 请求方式
- callback(function) - 回调函数
- meta(dict) - 数据传递。以下key是特殊值
- cookiejar(str) - 指定cookie标识
- dont_redirect(bool) - 是否自动跳转
- proxy(str) - 单独设置代理
- dont_redirect(bool) - 是否禁止跳转
- dont_retry(bool) - 是否禁止重试
- max_retry_times(int) - 最大重试次数。0不重试
- body(str, dict, list) - 请求数据,优先data和json
- data(str, dict, list) - 请求数据,优先json
- json(dict) - 请求json数据,仅body和data为空时。并且method会更新为POST
- headers(dict) - 更新请求头
- cookies(dict) - 额外cookies
- dont_filter(bool) - 是否过滤
- cb_kwargs(dict) - 回调函数的指定kw参数
_run_callback(response) - 保留函数,用于调用
class pycurl_session.spider.request.FormRequest(url, **args)
Parameters:
- url(str) - 请求链接
- **args - 其他Request()的参数
from_response(response, form_id=None, form_name="", form_num=0, method="POST", action=None, formdata=None, callback=None, **args)
Parameters:
- response(Response) - 响应类
- form_id(str) - 表单id
- form_name(str) - 表单名称
- form_num(int) - 表单序号。依次按form_id,form_name,form_num获取表单
- method(str) - 请求方式
- action(str) - 指定表单的action。默认会从获取的表单里拿
- formdata(dict) - 指定表单数据
- callback(function) - 回调函数
- **args - 其他Request()的参数
Return:
- Request
class pycurl_session.spider.exception.IgnoreRequest()
用于下载中间件。raise IgnoreRequest()
将丢弃Request。
class pycurl_session.spider.exception.DropItem()
用于Item管道。raise DropItem()
将丢弃Item。
class pycurl_session.spider.mailsender.MailSender(host=None, port=25, login_user=None, login_password=None, tls=False, ssl=True)
set_host(host, port=25, tls=False, ssl=True)
login(login_user, login_password)
send(mailfrom, mailto, subject, body, cc=None, attachs=(), minetype="text/plain", charset="utf-8")
class MyDownloadMiddleware:
def __init__(self):
self.request_count = 0
self.response_count = 0
def process_request(self, request, spider):
self.request_count += 1
def process_response(self, request, response, spider):
self.response_count += 1
def process_exception(self, request, exception, spider):
logger = spider._get_logger()
logger.error("ERROR: {0}, {1}".format(exception.errno, exception.errmsg))
def process_logstat(self):
return {"my_count": {"request_count": self.request_count, "response_count": self.response_count}}
if __name__ == "__main__":
settings = {
"DOWNLOADER_MIDDLEWARES": ["MyDownloadMiddleware"]
}
schedule = Schedule(settings)
DOWNLOADER_MIDDLEWARES的元素支持package_path.Class
形式。如果只有Class
,将会尝试从当前运行文件导入。
class ItemCount:
def __init__(self) -> None:
self.count = 0
def process_item(self, item, spider):
spider.log(item)
self.count += 1
def close_spider(self, spider):
spider.log("total: " + str(self.count))
if __name__ == "__main__":
settings = {
"ITEM_PIPELINES": ["ItemCount"]
}
schedule = Schedule(settings)
ITEM_PIPELINES的元素支持package_path.Class
形式。如果只有Class
,将会尝试从当前运行文件导入。
from pycurl_session.spider.task import TaskItem, Task
class MyTask(Task):
def __init__(self, spider): # Spider instance. not support other args
super().__init__(self, spider)
self.start_urls = []
file_path = "url.txt"
with open(file_path, "r") as f:
for line in f.readline():
self.start_urls.append(line)
def get(self):
if len(self.start_urls):
url = self.start_urls.pop()
request = Request(url=url, callback=self.spider.parse, headers={"referer": None})
return TaskItem(self.spider.spider_id, request)
return None
if __name__ == "__main__":
schedule = Schedule(settings)
schedule.add_spider(Test, task_provider=MyTask)
Task初始化只支持传入Spider实例,即add_spider()的第一个参数,经过实例化后传入。
- 没有Command line tool,没有project功能
- 没有Item()/ItemLoader()
- 没有Feed exports
- 没有Spider Middleware
- 使用pycurl.CurlMulti做多线程。Scrapy里,使用Twisted做调度
- Selector支持re()但和Scrapy里的不一样
- Selector通过get()/getall()/re()/[index]获取的结果不再是Selector。Scrapy里,支持r.xpath()[0].getall()
- 没有Selector.remove_namespaces()。
- 只支持process_item()和close_spider()
- 只支持process_request(), process_response()和process_exception()。没有from_crawler()
- 有body参数,实际使用data,但不支持bytes类型
- 参数没有errback。目前错误处理还不完善
- 参数没有priority/encoding/flags
- from_response()参数没有clickdata/dont_click
- 没有JsonRequest(),可以通过Request()的json参数
- body是str类型,只读。可以通过text设置。在Scrapy里body是bytes类型
- 没有copy()/replace()/follow()/follow_all()函数