scrapy的主要组成:
- spider.py
- items.py
- middlewares.py
- pipelines.py
- settings.py
spiders.py 负责的是对网页,对链接如何处理的部分。
# -*- coding: utf-8 -*-
from scrapy import Spider, Request # 这里改写了引用方便点
from ..items import BaiduItem # 导入 item
class BdSpider(Spider):
name = 'bd' # spider 名称
allowed_domains = ['baidu.com'] # 过滤的域名,对 strat_urls 不过滤
start_urls = ['http://baidu.com/'] # 必须是列表形式
url = 'https://www.baidu.com/s?wd={}&ie=utf-8'
def start_requests(self): # 对 start_urls 里面的链接进行请求处理
。。。。。(一顿操作, response.xpath(), re 之类的)
yield Request(self.url.format(word), callback=self.get_url) # 对目标链接的下一步操作
def get_url(self, response):
item = BaiduItem() # 使用item
。。。。。(一顿操作)
yield Request(i, callback=self.get_name, headers={'HOST':
'koubei.baidu.com'},meta ={'data':item})
# 单独设定请求头,优先度更加高, meta 是传递item给下一个目标函数
def get_name(self, response)
item = response.meta['data'] # 引用出传递的item
yield item # 传递 item 给 pipeline 处理
items.py 是确定要保存的数据种类。
import scrapy
class BaiduItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
name = scrapy.Field() # 每个要保存的数据都是这种格式
middleware.py 是每个请求的中间件,可以为请求添加代理,请求头,根据的出错的响应的状态码来处理异常等。
下面是一个添加代理的例子。
from scrapy import signals
import base64
import requests
import json
import time
import random
import datetime
class ProxyMiddleware(object):
def process_request(self, request, spider):
res = requests.get(‘这里用request请求,不要用scrapy自带的,因为自带的如果开了代理的设置,就成了用请求的代理来作为自己的代理来请求, dead loop ’)
# 这里用的是讯代理生成json的api
con = json.loads(res.text)
if con['ERRORCODE'] == 0:
proxies_pool = con['RESULT']
for proxy in proxies_pool:
result = proxy['ip'] + ':' + proxy['port']
requset.meta['proxy'] = result # 加入代理
# 随机选出代理信息(这是一个账号密码验证的api)
proxy = "xxxxx:23128"
# 设置代理的认证信息
auth = base64.b64encode(bytes(" 账号 : 密码 ", 'utf-8'))
request.headers['Proxy-Authorization'] = b'Basic ' + auth # ‘’Basic ‘’后面带了一个空格
# 设置代理ip (http/https)
request.meta['proxy'] = 'http://' + proxy
# 定时更新代理的例子
def __init__(self):
self.url = ' api
self.proxy = ''
# 一开始没有请求api,所以是空的,需要减去空隔时间,一开始才能运行
self.expire_datetime = datetime.datetime.now() - datetime.timedelta(
seconds=15)
self._check_expire() # 前面加横线是确保只被自身调用
# 定时获取代理
def _get_proxyip(self):
res = requests.get(self.url)
result = json.loads(res.text)
if result['ERRORCODE'] == 0:
pro_addr = 'http://' + result['RESULT']['wanIp'] + ':' + result[
'RESULT']['proxyport']
self.proxy = pro_addr
self.expire_datetime = datetime.datetime.now() + \
datetime.timedelta(seconds=15)
# 有效时间
def _check_expire(self):
if datetime.datetime.now() >= self.expire_datetime:
self._get_proxyip()
# 配置代理地址
def process_request(self, request, spider):
self._check_expire()
request.meta['proxy'] = self.proxy
# 取本地存在txt的ip地址
file = r'E://ip.txt'
with open(file, 'r') as f:
l = []
for i in f.readlines():
l.append(i.strip())
pro_addr = random.choice(l)
request.meta['proxy'] = pro_addr
pipelines.py 是对传递的 item 的处理及输出
import pymysql
class SavePipeline(object):
def __init__(self):
# 链接数据库
self.connect = pymysql.connect(host='host', user='user', passwd='password', db='db_name')
# get cursor
self.cursor = self.connect.cursor()
print("linked")
def process_item(self, item, spider):
# sql 语句
insert_sql = "
insert into xxx( item 的定义类型) VALUES (%s,%s,%s,%s,%s)
"
# 执行 sql 语句插入数据
self.cursor.execute(insert_sql, ( item 的值))
# 提交,不进行提交无法保存到数据库
self.connect.commit()
def close_spider(self, spider):
# 关闭游标和连接
self.cursor.close()
self.connect.close()
pipelines 设置好在 settings.py 开启
settings.py 是全局配置的文件
LOG_FILE = 'log.txt' # 保存日志到指定路径
# 日志的等级,可选的级别有: CRITICAL、ERROR、WARNING、INFO、DEBUG。
LOG_LEVEL = 'DEBUG'
# 输出文件的编码,防止中文乱码
FEED_EXPORT_ENCODING = 'UTF-8-SIG'
# 调整输出 csv 的 item 顺序
FEED_EXPORT_FIELDS = ["xxxx", "xxx", "xx","x"]
# RetryMiddleware 用到的
RETRY_HTTP_CODES = [500, 502, 503, 504, 400, 403, 404, 408]
# 忽略的状态码
HTTPCACHE_IGNORE_HTTP_CODES = []
设置优先级:命令行 > custom_settings > settings.py
引用 scrapy 的设置:
在 spider 中,
from ..settings import *
这个只能引用 settings.py 中的命令,当需要引用最高优先级的设置时,并不能做到。
所以使用 from_clawer
方法来获取最高优先级的设置。
Scrapy cookie 设置
当COOKIES_ENABLED是注释的时候scrapy默认没有开启cookie
当COOKIES_ENABLED没有注释设置为False的时候scrapy默认使用了settings里面的cookie
当COOKIES_ENABLED设置为True的时候scrapy就会把settings的cookie关掉,使用自定义cookie