你的爬虫被后台检测到了?这么做才能隐藏爬虫

前言

我们在写一个简单的爬虫时,爬虫代码很容易就会被后台检测到进而封掉。那么怎么样才能避免这些事发生呢?这一这篇文章我们一起来学习,如何健壮我们的爬虫代码。


目录

Spider

Middleware

瞎比比

Spider

当 start_urls 未被指定,会调用 start_requests() ,该方法可以用于在爬取数据之前,先进行模拟登陆。

import scrapy

from scrapy.http import Request

from scrapy.selector import Selector

from urllib.parse import urljoin

from doubanTop250.items import Doubantop250Item

class DoubanTop250Spider(scrapy.spiders.Spider):

# 此处为上面留下的小坑

name = "douban"

# 设置允许爬取的域名

allowed_domains = ["douban.com"]

# header信息

my_header = {

'Host': 'www.douban.com',

'Referer': 'https://movie.douban.com',

}

# 表单需要提交的数据

form_data = {'user': 'zone', 'pass': 'zone7'}

# 自定义信息,向下层响应(response)传递下去

customer_data = {'key1': 'value1', 'key2': 'value2'}

def start_requests(self):

return [scrapy.FormRequest("https://movie.douban.com/login",

formdata=self.form_data, # 表单提交的数据

headers=self.my_header,

method='POST', # GET or POST

meta=self.customer_data, # 自定义,向response传递数据

errback=self.error_handle,

callback=self.logged_in,

# 如果需要多次提交表单,且url一样,那么就必须加此参数 dont_filter,防止被当成重复网页过滤掉了

dont_filter=True

)]

def logged_in(self, response):

# 解析模拟登陆数据

pass

def parse(self, response):

# 默认回调函数

pass

def close(self,reson):

# 关闭时调用

pass

scrapy.FormRequest 部分参数解析

parse(self, response)

当 start_requests 没有指定回调函数时,默认回调 parse(self,response) 方法。parse 负责处理 response 并返回处理的数据以及(/或)跟进的 URL。

该方法及其他的 Request 回调函数必须返回一个包含 Request、dict 或 Item 的可迭代的对象。简单的来说,所谓的回调函数,其实就是告诉spider,在拿到了网站的 response 以后,交给谁来进行处理后面的页面的解析工作。这个看上一篇文章的代码就可以知道。

Middleware

这里说一下,关于自定义 middleware 需要重写的几个方法,可能你看完这一段长篇大论之后,还是懵逼的,没关系,我也是这样。不过,当你继续往下看,看一个实例之后,你就会明白。

process_request(request, spider)

当每个request通过下载中间件时,该方法被调用。

process_request() 必须返回其中之一: 返回 None 、返回一个 Response 对象、返回一个 Request 对象或 raise IgnoreRequest 。

如果其返回 None ,Scrapy将继续处理该request,执行其他的中间件的相应方法,直到合适的下载器处理函数(download handler)被调用, 该request被执行(其response被下载)。

如果其返回 Response 对象,Scrapy将不会调用 任何 其他的 process_request() 或 process_exception() 方法,或相应地下载函数; 其将返回该 response。 已安装的中间件的 process_response() 方法则会在每个 response 返回时被调用。

如果其返回 Request 对象,Scrapy则停止调用 process_request方法并重新调度返回的 request。当新返回的 request 被执行后, 相应地中间件链将会根据下载的 response 被调用。

如果其 raise 一个 IgnoreRequest 异常,则安装的下载中间件的 process_exception() 方法会被调用。如果没有任何一个方法处理该异常, 则 request 的errback(Request.errback) 方法会被调用。如果没有代码处理抛出的异常, 则该异常被忽略且不记录(不同于其他异常那样)。

参数:

request(Request 对象)–处理的 request

spider(Spider 对象)–该 request 对应的 spider

process_response(request, response, spider)

process_request() 必须返回以下之一: 返回一个 Response 对象、 返回一个 Request 对象或 raise 一个 IgnoreRequest 异常。

如果其返回一个 Response (可以与传入的response相同,也可以是全新的对象), 该response会被在链中的其他中间件的 process_response() 方法处理。

如果其返回一个 Request 对象,则中间件链停止, 返回的request会被重新调度下载。处理类似于 process_request() 返回request所做的那样。

如果其抛出一个 IgnoreRequest 异常,则调用 request 的 errback( Request.errback)。 如果没有代码处理抛出的异常,则该异常被忽略且不记录(不同于其他异常那样)。

参数:

request (Request 对象) – response 所对应的 request

response (Response 对象) – 被处理的 response

spider (Spider 对象) – response 所对应的 spider

process_exception(request, exception, spider)

当下载处理器(download handler)或 process_request() (下载中间件)抛出异常(包括IgnoreRequest异常)时,Scrapy调用 process_exception() 。

process_exception() 应该返回以下之一: 返回 None 、 一个 Response 对象、或者一个 Request 对象。

如果其返回 None ,Scrapy将会继续处理该异常,接着调用已安装的其他中间件的 process_exception() 方法,直到所有中间件都被调用完毕,则调用默认的异常处理。

如果其返回一个 Response 对象,则已安装的中间件链的 process_response() 方法被调用。Scrapy将不会调用任何其他中间件的 process_exception() 方法。

如果其返回一个 Request 对象, 则返回的request将会被重新调用下载。这将停止中间件的 process_exception() 方法执行,就如返回一个response的那样。

参数:

request (是 Request 对象) – 产生异常的request

exception (Exception 对象) – 抛出的异常

spider (Spider 对象) – request对应的spider

UserAgentMiddleware

多数情况下,网站都会通过 user-agent 来识别访问的用户是否为一台机器,就像爬取豆瓣一样,如果你没有设置 user-agent 的话,就会被拒绝访问。因此,我们只使用一个 user-agent 显然是不够的,因此,我们要想个办法来设置随机的 user-agent。于是,我们便可以自定义 UserAgentMiddleware 来解决这个问题。

首先,在 setting.py 中添加 user-agent ,如下:

MY_USER_AGENT = [

'MSIE (MSIE 6.0; X11; Linux; i686) Opera 7.23',

'iTunes/9.0.3 (Macintosh; U; Intel Mac OS X 10_6_2; en-ca)',

'Opera/9.20 (Macintosh; Intel Mac OS X; U; en)',

'Opera/9.0 (Macintosh; PPC Mac OS X; U; en)',

'Mozilla/4.76 [en_jp] (X11; U; SunOS 5.8 sun4u)',

'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6',

'Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5',

'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER',

'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',

'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',

'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',

'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)',

'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',

'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; 360SE)',

'Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)',

'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20',

'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6',

'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10',

'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER',

'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1',

'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)',

'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12',

'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)',

'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1',

'Mozilla/4.8 [en] (X11; U; SunOS; 5.7 sun4u)'

]

然后在 middlewares.py 中添加如下代码:

class MyUserAgentMiddleware(UserAgentMiddleware):

def __init__(self, user_agent):

self.user_agent = user_agent

@classmethod

def from_crawler(cls, crawler):

return cls(

user_agent=crawler.settings.get('MY_USER_AGENT')

)

def process_request(self, request, spider):

agent = random.choice(self.user_agent)

request.headers['User-Agent'] = agent

最后启用这个 middleware ,在 setting.py 中修改 MyUserAgentMiddleware 的优先级,如下:

DOWNLOADER_MIDDLEWARES = {

# 首先禁止其原有的 UserAgentMiddleware

'scrapy.downloadermiddleware.useragent.UserAgentMiddleware': None,

'doubanTop250.middlewares.MyUserAgentMiddleware': 300,

'doubanTop250.middlewares.ProxyMiddleware': 543,

}

ProxyMiddleware

除了要更改 user-agent 之外,我们还要使用 ip 代理来健壮我们的爬虫程序。那么,在 scrapy 中如何来设置我们的 ip 代理呢?

首先,在 setting.py 中添加如下代码,为代理 ip:

PROXIES = [

"194.186.20.62:21231"

, "66.153.222.162:54684"

, "219.234.5.128:3128"

, "117.114.149.66:53281"

, "117.114.149.66:53281"

]

ip 来自西刺代理,不过好像好多没用的代理。

然后在 middlewares.py 中添加如下代码:

from scrapy import signals

import random

class ProxyMiddleware(object):

def __init__(self, ip):

self.ip = ip

@classmethod

def from_crawler(cls, crawler):

return cls(ip=crawler.settings.get('PROXIES'))

def process_request(self, request, spider):

ip = random.choice(self.ip)

request.meta['proxy'] = ip

最后启用这个 middleware ,在 setting.py 中修改 ProxyMiddleware 的优先级,如下:

DOWNLOADER_MIDDLEWARES = {

# 首先禁止其原有的 UserAgentMiddleware

'scrapy.downloadermiddleware.useragent.UserAgentMiddleware': None,

'doubanTop250.middlewares.MyUserAgentMiddleware': 300,

'doubanTop250.middlewares.ProxyMiddleware': 543,

}

瞎比比

经过这些操作之后,你的代码等级就提升了一个高度了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352

推荐阅读更多精彩内容