scrapy绕过反爬虫

作者: M954 | 来源:发表于2017-11-16 21:30 被阅读180次

    这里还是用scrapy框架写的爬虫。
    最近才开始学习的,经过搜索了之后,常见的反爬虫方案大致有几个:
    1.针对用户行为,常见的就是网站会针对ip访问频率统计,访问太过频繁,会禁止该ip地址的访问
    2.判断Header,比如如果User-agent是爬虫或者检测工具,或者非正常的浏览器,就禁止该次连接
    3.数据加载方式,采用ajax异步加载,这样只是爬取静态页面的话什么信息都没有办法得到

    下面实现一下每一个方案的应对方案:

    1.针对用户行为
    针对用户行为基本上就是对ip地址的访问统计,还有同一个用户多次相同的行为什么的,不过这里是为了爬取url,基本不会有后者的情况。
    可以采用代理ip来解决,写一个爬虫爬取免费的代理网站,获取到一批免费代理,然后每次都随机选一个就好了。
    下面是爬取代理的代码,注意频率不要太高,免费的代理网站也是有反爬虫的。

    # -*- coding: utf-8 -*-
    import scrapy
    import time
    from scrapy.selector import Selector
    
    class Proxyspider(scrapy.Spider):
        name = 'proxy'
        allowed_domains = ['www.xicidaili.com']
        start_urls = ['http://www.xicidaili.com/']
    
        def start_requests(self):
            burl = "http://www.xicidaili.com/nn/"
            for i in range(1,5):
                yield scrapy.Request(url=burl+str(i), callback=self.parse)
    
        def parse(self, response):
    
            se = scrapy.Selector(response)
    
            cnt = 0
            site = se.xpath('//tr')
            for s in site:
                content = s.xpath('.//td/text()').extract()
                if len(content) > 2:
                    scheme = content[5]
                    if scheme == 'HTTP' or scheme == 'HTTPS':
                        print '%s://%s:%s'%(scheme.lower(), content[0], content[1])
    
    

    免费的代理不一定能用,需要先做一下测试

    # testproxy.py
    #encoding=utf8
    
    import urllib
    import requests
    import sys
    
    if __name__ == "__main__":
        for url in sys.stdin:
            resp = requests.get(url)
            if resp.status_code == requests.codes.ok:
                print url
    

    然后写个脚本,用crontab设置其定期运行,就可以愉快地更新代理啦。

    # updateproxy.sh
    
    set -x
    scrapy crawl proxy > tmp
    cat tmp > python updateproxy.sh > proxy
    

    crontab设置为每15分钟运行更新一次

    */15 * * * * cd /home/qiqi/spider/urlspider/urlspider && sh updateproxy.sh
    

    现在我们有了一批定期更新的代理了,需要在scrapy运行过程中加入代理就可以了。
    可以在发送请求的时候加上,也可以添加一个中间件,这里是添加了中间件。
    添加中间件的代码:

    # middlewares.py
    class ProxyMiddleware(object):
        def process_request(self, request, spider):
            f = open("proxy", "r")
            proxy = f.readlines()
            # print request.headers
            try:
                request.meta['proxy'] = random.choice(proxy)
            except Exception, e:
                print >> sys.stderr, e
    

    在设置setting.py中进行配置

    DOWNLOADER_MIDDLEWARES = {
        'tutorial.middlewares.ProxyMiddleware': 100,
    }
    

    这就完成了代理配置了。

    2.判断Header
    对这个只需要在请求时都构造一个header就可以了。
    user-agent:可以移步http://blog.csdn.net/bone_ace/article/details/52476016 这里提供了非常全的user-agent
    referer:可以填上一个爬取的页面

    myheader = {
                'referer': response.url,
                'user-agent': random.choice(UrlSpider.user_agent), #user_agent是从上面提到的文章中摘取的列表
            }
    yield scrapy.Request(url, self.parse, headers=myheader)
    

    3.数据加载方式
    scrapy+splash可以爬取JS生成的动态页面
    先安装splash

    sudo pip install scrapy-splash
    

    splash一般是运行在docker上面的,因此需要先下载docker

    sudo apt-get install docker
    

    然后拉取镜像运行

    sudo docker pull scrapinghub/splash
    docker run -p 8000:8000 scrapinghub/splash
    

    在setting.py中配置splash

    SPLASH_URL = 'http://127.0.0.1:8000'
    ...
    DOWNLOADER_MIDDLEWARES = {
     'tutorial.middlewares.ProxyMiddleware': 100,
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
    }
    ...
    SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
    }
    ...
    DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
    ...
    HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'
    

    然后修改spiders,将scrapy.Request替换为SplashRequest

    # -*- coding: utf-8 -*-
    import scrapy
    import urlparse
    import random
    from urlspider.items import UrlspiderItem
    from scrapy.selector import Selector
    from scrapy_splash import SplashRequest
    
    class UrlSpider(scrapy.Spider):
        name = 'url'
        allowed_domains = ['opencv.org']
        start_urls = ['http://opencv.org/']
        result_urls = []
        user_agent=[]
    
        black_list = ['.jpeg', '.jpg', '.png', '.gif',
                      '.css', '.json',
                      '.mp3', '.mp4',
                      '.zip', '.tar.gz', '.rar', '.7z']
    
        def start_requests(self):
            self.get_UA()
            for url in UrlSpider.start_urls:
                myheader = {
                    'referer': response.url,
                    'user-agent': random.choice(UrlSpider.user_agent), #user_agent是从上面提到的文章中摘取的列表
                }
                yield SplashRequest(url, self.parse, args={'wait': 1.0})
    
        def parse(self, response):
    
            item = UrlspiderItem()
            item['url'] = response.url
    
            se = Selector(response)
    
            result = set()
    
            site = se.xpath('//a/@href').extract()
            for s in site:
                tmpurl = urlparse.urljoin(response.url, s)
                if self.check_url(tmpurl):
                    continue
                if tmpurl not in result:
                    result.add(tmpurl)
    
            myheader = {
                'referer': response.url,
                'user-agent': random.choice(UrlSpider.user_agent), #user_agent是从上面提到的文章中摘取的列表
            }
            for r in result:
                if r not in UrlSpider.result_urls:
                    UrlSpider.result_urls.append(r)
                    yield SplashRequest(url, self.parse, header=myheader, args={'wait': 1.0})
    
            yield item
    
        def get_UA(self):
            for line in open('UA'):
                UrlSpider.user_agent.append(line)
    
        def check_url(self, url):
            tmp = urlparse.urlparse(url)
            res = False
            for i in UrlSpider.black_list:
                print tmp['path']
                if i in tmp['path']:
                     res = True
                     return res
            return res
    

    这样就可以获取到JS动态加载生成的页面了。

    相关文章

      网友评论

        本文标题:scrapy绕过反爬虫

        本文链接:https://www.haomeiwen.com/subject/ukhhvxtx.html