403 forbidden怎么解决,高级网络爬虫技术

大家好,关于403 forbidden怎么解决很多朋友都还不太明白,今天小编就来为大家分享关于高级网络爬虫技术的知识,希望对各位有所帮助!

想要学习Python。关注小编头条号,私信【学习资料】,即可免费领取一整套系统的板Python学习教程!

建立工程项目

我们会在virtualenv中建立我们的项目,这可以让我们封装一下依赖关系。首先我们在~/scrapers/zipru中创建一个virtualenv,并且安装scrapy包。

mkdir~/scrapers/zipruncd~/scrapers/ziprunvirtualenvenvn.env/bin/activatenpipinstallscrapyn

你运行的终端将被配置为使用本地的virtualenv。如果你打开另一个终端,那么你就需要再次运行.~/scrapers/zipru/env/bin/active命令(否则你有可能得到命令或者模块无法找到的错误消息)。

现在你可以通过运行下面的命令来创建一个新的项目框架:

scrapystartprojectzipru_scrapern

这样就会创建下面的目录结构。

└──zipru_scrapern├──zipru_scrapern│├──__init__.pyn│├──items.pyn│├──middlewares.pyn│├──pipelines.pyn│├──settings.pyn│└──spidersn│└──__init__.pyn└──scrapy.cfgn

大多数默认情况下产生的这些文件实际上不会被用到,它们只是建议以一种合理的方式来构建我们的代码。从现在开始,你应该把~/scrapers/zipru/zipru_scraper当做这个项目的根目录。这里是任何scrapy命令运行的目录,同时也是所有相对路径的根。

添加一个基本的爬虫功能

现在我们需要添加一个Spieder类来让我们的scrapy真正地做一些事情。Spider类是scrapy爬虫用来解析文本,爬取新的url链接或是提取数据的一个类。我们非常依赖于默认Spider类的实现,以最大限度地减少我们必须要编写的代码量。这里要做的事情看起来有点自动化,但假如你看过文档,事情会变得更加简单。

首先,在zipru_scraper/spiders/目录下创建一个文件,命名为zipru_spider.py,输入下面内容。

importscrapynclassZipruSpider(scrapy.Spider):nname='zipru'nstart_urls=['http://zipru.to/torrents.php?category=TV']n

你可以在上面的网页中看到许多指向其他页面的连接。我们想让我们的爬虫跟踪这些链接,并且解析他们的内容。为了完成这个任务,我们首先需要识别出这些链接并且弄清楚他们指向的位置。

在这个阶段,DOM检查器将起到很大的助力。如果你右击其中的一个页面链接,在DOM检查器里面查看它,然后你就会看到指向其他页面的链接看起来像是这样的:

<ahref="/torrents.php?...page=2"title="page2">2</a>n<ahref="/torrents.php?...page=3"title="page3">3</a>n<ahref="/torrents.php?...page=4"title="page4">4</a>n

接下来我们需要为这些链接构造一个选择器表达式。有几种类型似乎用css或者xpath选择器进行搜索更适合,所以我通常倾向于灵活地混合使用这几种选择器。我强烈推荐学习xpath,但是不幸的是,它有点超出了本教程的范围。我个人认为xpath对于网络爬虫,webUI测试,甚至一般的web开发来说都是不可或缺的。我接下来仍然会使用css选择器,因为它对于大多数人来说可能比较熟悉。

要选择这些页面链接,我们可以把a[title~=page]作为一个css选择器,来查找标题中有“page”字符的<a>标签。如果你在DOM检查器中按ctrl-f,那么你就会发现你也可以使用这个css表达式作为一条查找语句(也可以使用xpath)。这样我们就可以循环查看所有的匹配项了。这是一个很棒的方法,可以用来检查一个表达式是否有效,并且表达式足够明确不会在不小心中匹配到其他的标签。我们的页面链接选择器同时满足了这两个条件。

为了讲解我们的爬虫是怎样发现其他页面的,我们在ZipruSpider类中添加一个parse(response)方法,就像下面这样:

defparse(self,response):n#proceedtootherpagesofthelistingsnforpage_urlinresponse.css('a[title~=page]::attr(href)').extract():npage_url=response.urljoin(page_url)nyieldscrapy.Request(url=page_url,callback=self.parse)n

当我们开始爬取的时候,我们添加到start_urls中的链接将会被自动获取到,响应内容会被传递到parse(response)方法中。之后我们的代码就会找到所有指向其他页面的链接,并且产生新的请求对象,这些请求对象将使用同一个parse(response)作为回调函数。这些请求将被转化成响应对象,只要url仍然产生,响应就会持续地返回到parse(response)函数(感谢去重器)。

我们的爬虫已经可以找到了页面中列出的所有不同的页面,并且对它们发出了请求,但我们仍然需要提取一些对爬虫来说有用的数据。torrent列表位于<table>标签之内,并且有属性class="list2at",每个单独的torrent都位于带有属性class="lista2"的<tr>标签,其中的每一行都包含8个<td>标签,分别与“类别”,“文件”,“添加时间”,“文件大小”,“保种的人”,“下载文件的人”,“文件描述”,和“上传者”相对应。在代码中查看其它的细节可能是最简单的方法,下面是我们修改后的parse(response)方法:

defparse(self,response):n#proceedtootherpagesofthelistingsnforpage_urlinresponse.xpath('//a[contains(@title,"page")]/@href').extract():npage_url=response.urljoin(page_url)nyieldscrapy.Request(url=page_url,callback=self.parse)nn#extractthetorrentitemsnfortrinresponse.css('table.lista2ttr.lista2'):ntds=tr.css('td')nlink=tds[1].css('a')[0]nyield{n'title':link.css('::attr(title)').extract_first(),n'url':response.urljoin(link.css('::attr(href)').extract_first()),n'date':tds[2].css('::text').extract_first(),n'size':tds[3].css('::text').extract_first(),n'seeders':int(tds[4].css('::text').extract_first()),n'leechers':int(tds[5].css('::text').extract_first()),n'uploader':tds[7].css('::text').extract_first(),n}n

我们的parse(response)方法现在能够返回字典类型的数据,并且根据它们的类型自动区分请求。每个字典都会被解释为一项,并且作为爬虫数据输出的一部分。

如果我们只是爬取大多数常见的网站,那我们已经完成了。我们只需要使用下面的命令来运行:

scrapycrawlzipru-otorrents.jln

几分钟之后我们本应该得到一个[JSONLines]格式torrents.jl文件,里面有我们所有的torrent数据。取而代之的是我们得到下面的错误信息(和一大堆其他的东西):

[scrapy.extensions.logstats]INFO:Crawled0pages(at0pages/min),scraped0items(at0items/min)n[scrapy.extensions.telnet]DEBUG:Telnetconsolelisteningon127.0.0.1:6023n[scrapy.core.engine]DEBUG:Crawled(403)<GEThttp://zipru.to/robots.txt>(referer:None)['partial']n[scrapy.core.engine]DEBUG:Crawled(403)<GEThttp://zipru.to/torrents.php?category=TV>(referer:None)['partial']n[scrapy.spidermiddlewares.httperror]INFO:Ignoringresponse<403http://zipru.to/torrents.php?category=TV>:HTTPstatuscodeisnothandledornotallowedn[scrapy.core.engine]INFO:Closingspider(finished)n

我好气啊!我们现在必须变得更聪明来获得我们完全可以从公共API得到的数据,因为上面的代码永远都无法爬取到那些数据。

简单的问题

我们的第一个请求返回了一个403响应,所以这个url被爬虫忽略掉了,然后一切都关闭了,因为我们只给爬虫提供了一个url链接。同样的请求在网页浏览器里运行正常,即使是在没有会话(session)历史的隐匿模式也可以,所以这一定是由于两者请求头信息的差异造成的。我们可以使用tcpdump来比较这两个请求的头信息,但其实有个常见错误,所以我们应该首先检查:useragent。

Scrapy默认把user-agent设置为“Scrapy/1.3.3(+http://scrapy.org)“,一些服务器可能会屏蔽这样的请求,甚至使用白名单只允许少量的useragent通过。你可以在线查看最常见的useragent,使用其中任何一个通常就足以绕过基本反爬虫策略。选择一个你最喜欢的User-agent,然后打开zipru_scraper/settings.py,替换Useragent

#Crawlresponsiblybyidentifyingyourself(andyourwebsite)ontheuser-agentn#USER_AGENT='zipru_scraper(+http://www.yourdomain.com)'n

使用下面内容替换USER_AGENT:

USER_AGENT='Mozilla/5.0(Macintosh;IntelMacOSX10_10_5)AppleWebKit/537.36(KHTML,likeGecko)Chrome/55.0.2883.95Safari/537.36'n

你可能注意到了,默认的scrapy设置中有一些令爬虫蒙羞的事。关于这个问题的观点众说纷纭,但是我个人认为假如你想让爬虫表现的像是一个人在使用普通的网页浏览器,那么你就应该把你的爬虫设置地像普通的网络浏览器那样。所以让我们一起添加下面的设置来降低一下爬虫响应速度:

CONCURRENT_REQUESTS=1nDOWNLOAD_DELAY=5n

通过AutoThrottle扩展,上面的设置会创建一个稍微真实一点的浏览模式。我们的爬虫在默认情况下会遵守robots.txt,所以现在我们的行为非常检点。

现在使用scrapycrawlzipru-otorrents.jl命令再次运行爬虫,应该会产生下面的输出:

[scrapy.core.engine]DEBUG:Crawled(200)<GEThttp://zipru.to/robots.txt>(referer:None)n[scrapy.downloadermiddlewares.redirect]DEBUG:Redirecting(302)to<GEThttp://zipru.to/threat_defense.php?defense=1&r=78213556>from<GEThttp://zipru.to/torrents.php?category=TV>n[scrapy.core.engine]DEBUG:Crawled(200)<GEThttp://zipru.to/threat_defense.php?defense=1&r=78213556>(referer:None)['partial']n[scrapy.core.engine]INFO:Closingspider(finished)n

这是一个巨大的进步!我们获得了两个200状态码和一个302状态码,下载中间件知道如何处理302状态码。不幸的是,这个302将我们的请求重定向到了一个看起来不太吉利的页面threat_defense.php。不出所料,爬虫没有发现任何有用的东西,然后爬虫就停止运行了。

注:假如网站检测到你的爬虫,那么网站就会把你的请求重定向到threat_defense.php页面,使你的爬虫失效,用来防止频繁的爬虫请求影响了网站正常用户的使用。

下载中间件

在我们深入研究我们目前所面临的更复杂的问题之前,先了解一下请求和响应在爬虫中是怎样被处理的,将会很有帮助。当我们创建了我们基本的爬虫,我们生成了一个scrapy.Request对象,然后这些请求会以某种方法转化为与服务器的响应相对应的scrapy.Response对象。这里的“某种方法”很大一部分是来自于下载中间件。

下载中间件继承自scrapy.downloadermiddlewares.DownloaderMiddleware类并且实现了process_request(request,spider)和process_response(request,response,spider)方法。你大概可以从他们的名字中猜到他们是做什么的。实际上这里有一大堆的默认开启的中间件。下面是标准的中间件配置(你当然可以禁用、添加或是重新设置这些选项):

DOWNLOADER_MIDDLEWARES_BASE={n'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware':100,n'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware':300,n'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware':350,n'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware':400,n'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware':500,n'scrapy.downloadermiddlewares.retry.RetryMiddleware':550,n'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware':560,n'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware':580,n'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware':590,n'scrapy.downloadermiddlewares.redirect.RedirectMiddleware':600,n'scrapy.downloadermiddlewares.cookies.CookiesMiddleware':700,n'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware':750,n'scrapy.downloadermiddlewares.stats.DownloaderStats':850,n'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware':900,n}n

当一个请求到达服务器时,他们会通过每个这些中间件的process_request(request,spider)方法。这是按照数字顺序发生的,RobotsTxtMiddleware中间件首先产生请求,并且HttpCacheMiddleware中间件最后产生请求。一旦接收到一个响应,它就会通过任何已启用的中间件的process_response(request,response,spider)方法来返回响应。这次是以相反的顺序发生的,所以数字越高越先发送到服务器,数字越低越先被爬虫获取到。

一个特别简单的中间件是CookiesMiddleware。它简单地检查响应中请求头的Set-Cookie,并且保存cookie。然后当响应返回的时候,他们会适当地设置Cookie请求头标记,这样这些标记就会被包含在发出的请求中了。这个由于时间太久的原因要比我们说的要稍微复杂些,但你会明白的。

另一个相对基本的就是RedirectMiddleware中间件,它是用来处理3XX重定向的。它让一切不是3XX状态码的响应都能够成功的通过,但假如响应中还有重定向发生会怎样?唯一能够弄清楚服务器如何响应重定向URL的方法就是创建一个新的请求,而且这个中间件就是这么做的。当process_response(request,response,spider)方法返回一个请求对象而不是响应对象的时候,那么当前响应就会被丢弃,一切都会从新的请求开始。这就是RedirectMiddleware中间件怎样处理重定向的,这个功能我们稍后会用到。

如果你对于有那么多的中间件默认是开启的感到惊讶的话,那么你可能有兴趣看看体系架构概览。实际上同时还有很多其他的事情在进行,但是,再说一次,scrapy的最大优点之一就是你不需要知道它的大部分原理。你甚至不需要知道下载中间件的存在,却能写一个实用的爬虫,你不必知道其他部分就可以写一个实用的下载中间件。

困难的问题

回到我们的爬虫上来,我们发现我们被重定向到某个threat_defense.php?defense=1&...URL上,而不是我们要找的页面。当我们在浏览器里面访问这个页面的时候,我们看到下面的东西停留了几秒:

在被重定向到threat_defense.php?defense=2&...页面之前,会出现像下面的提示:

看看第一个页面的源代码就会发现,有一些javascript代码负责构造一个特殊的重定向URL,并且构造浏览器的cookies。如果我们想要完成这个任务,那我们就必须同时解决上面这两个问题。

接下来,当然我们也需要解决验证码并提交答案。如果我们碰巧弄错了,那么我们有时会被重定向到另一个验证码页面,或者我们会在类似于下面的页面上结束访问:

在上面的页面中,我们需要点击“Clickhere”链接来开始整个重定向的循环,小菜一碟,对吧?

我们所有的问题都源于最开始的302重定向,因此处理它们的方法自然而然应该是做一个自定义的重定向中间件。我们想让我们的中间件在所有情况下都像是正常重定向中间件一样,除非有一个302状态码并且请求被重定向到threat_defense.php页面。当它遇到特殊的302状态码时,我们希望它能够绕过所有的防御机制,把访问cookie添加到session会话中,最后重新请求原来的页面。如果我们能够做到这一点,那么我们的Spider类就不必知道这些事情,因为请求会全部成功。

打开zipru_scraper/middlewares.py文件,并且把内容替换成下面的代码:

importos,tempfile,time,sys,loggingnlogger=logging.getLogger(__name__)nnimportdryscrapenimportpytesseractnfromPILimportImagennfromscrapy.downloadermiddlewares.redirectimportRedirectMiddlewarennclassThreatDefenceRedirectMiddleware(RedirectMiddleware):ndef_redirect(self,redirected,request,spider,reason):n#actnormallyifthisisn'tathreatdefenseredirectnifnotself.is_threat_defense_url(redirected.url):nreturnsuper()._redirect(redirected,request,spider,reason)nnlogger.debug(f'Zipruthreatdefensetriggeredfor{request.url}')nrequest.cookies=self.bypass_threat_defense(redirected.url)nrequest.dont_filter=True#preventstheoriginallinkbeingmarkedadupenreturnrequestnndefis_threat_defense_url(self,url):nreturn'://zipru.to/threat_defense.php'inurln

你可能注意到我们继承了RedirectMiddleware类,而不是直接继承DownloaderMiddleware类。这样就允许我们重用大部分的重定向处理函数,并且把我们的代码插入到_redirect(redirected,request,spider,reason)函数中,一旦有重定向的请求被创建,process_response(request,response,spider)函数就会调用这个函数。我们只是把对于普通的重定向的处理推迟到父类进行处理,但是对于特殊的威胁防御重定向的处理是不一样的。我们到目前为止还没有实现bypass_threat_defense(url)方法,但是我们可以知道它应该返回访问cookies,并把它附加到原来的请求中,然后原来的请求将被重新处理。

为了开启我们新的中间件,我们需要把下面的内容添加到zipru_scraper/settings.py中:

DOWNLOADER_MIDDLEWARES={n'scrapy.downloadermiddlewares.redirect.RedirectMiddleware':None,n'zipru_scraper.middlewares.ThreatDefenceRedirectMiddleware':600,n}n

这会禁用默认的重定向中间件,并且把我们的中间件添加在中间件堆栈中和默认重定向中间件相同的位置。我们必须安装一些额外的包,虽然我们现在没有用到,但是稍后我们会导入它们:

pipinstalldryscrape#headlesswebkitnpipinstallPillow#imageprocessingnpipinstallpytesseract#OCRn

请注意,这三个包都有pip无法处理的外部依赖,如果你运行出错,那么你可能需要访问dryscrape,Pillow,和pytesseract的安装教程,遵循平台的具体说明来解决。

我们的中间件现在应该能够替代原来的标准重定向中间件,现在我们只需要实现bypass_thread_defense(url)方法。我们可以解析javascript代码来得到我们需要的变量,然后用python重建逻辑,但这看起来很不牢靠,而且需要大量的工作。让我们采用更简单的方法,尽管可能还是比较笨重,使用无头的webkit实例。有几个不同选择,但我个人比较喜欢dryscrape(我们已经在上面安装了)

首先,让我们在中间件构造函数中初始化一个dryscrape会话。

def__init__(self,settings):nsuper().__init__(settings)nn#startxvfbtosupportheadlessscrapingnif'linux'insys.platform:ndryscrape.start_xvfb()nnself.dryscrape_session=dryscrape.Session(base_url='http://zipru.to')n

你可以把这个会话对象当做是一个单独的浏览器标签页,它可以完成一切浏览器通常可以做的事情(例如:获取外部资源,执行脚本)。我们可以在新的标签页中打开新的URL链接,点击一些东西,或者在输入框中输入内容,或是做其他的各种事情。Scrapy支持并发请求和多项处理,但是响应的处理是单线程的。这意味着我们可以使用这个单独的dryscrapy会话,而不必担心线程安全。

现在让我们实现绕过威胁防御机制的基本逻辑。

defbypass_threat_defense(self,url=None):n#onlynavigateifanyexpliciturlisprovidednifurl:nself.dryscrape_session.visit(url)nn#solvethecaptchaifthereisonencaptcha_images=self.dryscrape_session.css('img[src*=captcha]')niflen(captcha_images)>0:nreturnself.solve_captcha(captcha_images[0])nn#clickonanyexplicitretrylinksnretry_links=self.dryscrape_session.css('a[href*=threat_defense]')niflen(retry_links)>0:nreturnself.bypass_threat_defense(retry_links[0].get_attr('href'))nn#otherwise,we'reonaredirectpagesowaitfortheredirectandtryagainnself.wait_for_redirect()nreturnself.bypass_threat_defense()nndefwait_for_redirect(self,url=None,wait=0.1,timeout=10):nurl=urlorself.dryscrape_session.url()nforiinrange(int(timeout//wait)):ntime.sleep(wait)nifself.dryscrape_session.url()!=url:nreturnself.dryscrape_session.url()nlogger.error(f'Maybe{self.dryscrape_session.url()}isn\'taredirectURL?')nraiseException('Timedoutonthezipruredirectpage.')n

这样就处理了我们在浏览器中遇到的所有不同的情况,并且完全符合人类在每种情况中的行为。在任何给定情况下采取的措施都取决于当前页面的情况,所以这种方法可以稍微优雅一点地处理各种不同的情况。

最后一个难题是如果如何解决验证码。网上提供了验证码识别服务,你可以在必要时使用它的API,但是这次的这些验证码非常简单,我们只用OCR就可以解决它。使用pytessertact的OCR功能,最后我们可以添加solve_captcha(img)函数,这样就完善了bypass_threat_defense()函数。

defsolve_captcha(self,img,width=1280,height=800):n#takeascreenshotofthepagenself.dryscrape_session.set_viewport_size(width,height)nfilename=tempfile.mktemp('.png')nself.dryscrape_session.render(filename,width,height)nn#injectjavascripttofindtheboundsofthecaptchanjs='document.querySelector("img[src*=captcha]").getBoundingClientRect()'nrect=self.dryscrape_session.eval_script(js)nbox=(int(rect['left']),int(rect['top']),int(rect['right']),int(rect['bottom']))nn#solvethecaptchainthescreenshotnimage=Image.open(filename)nos.unlink(filename)ncaptcha_image=image.crop(box)ncaptcha=pytesseract.image_to_string(captcha_image)nlogger.debug(f'SolvedtheZiprucaptcha:"{captcha}"')nn#submitthecaptchaninput=self.dryscrape_session.xpath('//input[@id="solve_string"]')[0]ninput.set(captcha)nbutton=self.dryscrape_session.xpath('//button[@id="button_submit"]')[0]nurl=self.dryscrape_session.url()nbutton.click()nn#tryagainifitweredirecttoathreatdefenseURLnifself.is_threat_defense_url(self.wait_for_redirect(url)):nreturnself.bypass_threat_defense()nn#otherwisereturnthecookiesasadictncookies={}nforcookie_stringinself.dryscrape_session.cookies():nif'domain=zipru.to'incookie_string:nkey,value=cookie_string.split(';')[0].split('=')ncookies[key]=valuenreturncookiesn

你可能注意到如果验证码因为某些原因识别失败的话,它就会委托给backtothebypass_threat_defense()函数。这样就给了我们多次识别验证码的机会,但重点是,我们会在得到正确结果之前一直在验证码识别过程中循环。

这应该足够让我们的爬虫工作,但是它有可能陷入死循环中。

[scrapy.core.engine]DEBUG:Crawled(200)<GEThttp://zipru.to/robots.txt>(referer:None)n[zipru_scraper.middlewares]DEBUG:Zipruthreatdefensetriggeredforhttp://zipru.to/torrents.php?category=TVn[zipru_scraper.middlewares]DEBUG:SolvedtheZiprucaptcha:"UJM39"n[zipru_scraper.middlewares]DEBUG:Zipruthreatdefensetriggeredforhttp://zipru.to/torrents.php?category=TVn[zipru_scraper.middlewares]DEBUG:SolvedtheZiprucaptcha:"TQ9OG"n[zipru_scraper.middlewares]DEBUG:Zipruthreatdefensetriggeredforhttp://zipru.to/torrents.php?category=TVn[zipru_scraper.middlewares]DEBUG:SolvedtheZiprucaptcha:"KH9A8"n...n

至少看起来我们的中间件已经成功地解决了验证码,然后补发了请求。问题在于,新的请求再次触发了威胁防御机制。我第一个想法是我可能在怎样解析或是添加cookie上面有错误,但是我检查了三次,代码是正确的。这是另外一种情况“唯一可能不同的事情就是请求头”。

很明显,scrapy和dryscrape的请求头都绕过了最初的触发403响应的过滤器,因为我们现在不会得到任何403的响应。这肯定是因为它们的请求头信息不一致导致的。我的猜测是其中一个加密的访问cookies包含了整个请求头信息的散列值,如果这个散列不匹配,就会触发威胁防御机制。这样的目的可能是防止有人把浏览器的cookie复制到爬虫中去,但是它只是增加了你需要解决的问题而已。

所以让我们在zipru_scraper/settings.py中把请求头信息修改成下面这个样子。

DEFAULT_REQUEST_HEADERS={n'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',n'User-Agent':USER_AGENT,n'Connection':'Keep-Alive',n'Accept-Encoding':'gzip,deflate',n'Accept-Language':'en-US,*',n}n

注意我们已经把User-Agent头信息修改成了我们之前定义的USER_AGENT中去.这个工作是由useragent中间件自动添加进去的,但是把所有的这些配置放到一个地方可以使得dryscrape更容易复制请求头信息。我们可以通过修改ThreatDefenceRedirectMiddleware初始化函数像下面这样:

def__init__(self,settings):nsuper().__init__(settings)nn#startxvfbtosupportheadlessscrapingnif'linux'insys.platform:ndryscrape.start_xvfb()nnself.dryscrape_session=dryscrape.Session(base_url='http://zipru.to')nforkey,valueinsettings['DEFAULT_REQUEST_HEADERS'].items():n#seemstobeabugwithhowwebkit-serverhandlesaccept-encodingnifkey.lower()!='accept-encoding':nself.dryscrape_session.set_header(key,value)n

现在,当我们可以通过命令scrapycrawlzipru-otorrents.jl再次运行爬虫。我们可以看到源源不断的爬取的内容,并且我们的torrents.jl文件记录把爬取的内容全部记录了下来。我们已经成功地绕过了所有的威胁防御机制。

总结

我们已经成功地写了一个能够解决四种截然不同的威胁防御机制的爬虫,这四种防御机制分别是:

Useragent过滤模糊的Javascript重定向验证码请求头一致性检查

我们的目标网站Zipru可能是虚构的,但是这些机制都是你会在真实网站上遇到的真实的反爬虫技术。希望我们使用的方法对你自己爬虫中遇到的挑战有帮助。

想要学习Python。关注小编头条号,私信【学习资料】,即可免费领取一整套系统的板Python学习教程!

文章到此结束,如果本次分享的403 forbidden怎么解决和高级网络爬虫技术的问题解决了您的问题,那么我们由衷的感到高兴!