scrapy爬虫与反爬虫

scrapy爬虫与反爬虫

更多文章欢迎访问个人博客 www.herobin.top

爬虫和反爬虫

  • 爬虫:自动获取网站数据的程序,关键是批量的获取
  • 反爬虫:使用技术手段防止爬虫程序的方法
  • 误伤:反爬技术将普通用户识别为爬虫,如果误伤过高,效果再好也不能用
  • 成本:反爬虫需要的人力和机器成本
  • 拦截:成功拦截爬虫,一般拦截率越高,误伤率越高

反爬虫的目的

  • 初级爬虫:简单粗暴,不管服务器压力,容易弄挂网站
  • 数据保护
  • 失控的爬虫:由于某些情况下,忘记或者无法关闭的爬虫
  • 商业竞争对手

爬虫和反爬虫对抗过程

爬虫和网站攻坚过程

  • 爬虫:分析网络请求,用scrapy写爬虫爬取数据
  • 网站:监控发现某个时间段访问陡增,ip相同,useragent都是python,直接限制访问(不能封ip)
  • 爬虫:User-agent模拟firefox,获取ip代理
  • 网站:发现ip变化,直接要求登录才能访问
  • 爬虫:注册账号,每次请求带cookie或者token
  • 网站:健全账号体系,即A只能访问好友的信息
  • 爬虫:注册多个账号,多个账号联合爬取
  • 网站:请求过于频繁,进一步加剧ip访问频率限制
  • 爬虫:模仿人请求,限制请求速度
  • 网站:弹出验证码,让识别验证码
  • 爬虫:通过各种手段识别验证码
  • 网站:1.增加动态网站,数据通过js动态加载,增加网络分析复杂
    2.发现大量请求只请求html,不请求image和css以及js
  • 爬虫:通过selenium和phantomjs完全模拟浏览器操作
  • 网站:成本太高,放弃…

在这里插入图片描述

随机调用User-agent

settings.py
 user_agent_list = [
"","",....
] 
zhihu.py
from settings import user_agent_list
import random
random_index = random.randint(0, len(user_agent_list)-1)
random_agent = user_agent_list[random_index]
headers = {
"User-agent": random_agent,
...
}

然而这样代码冗余了

从上面流程图可以看到每次访问(4)都会请求MiddleWare,可以在settings中将DOWNLOADER_MIDDLEWARES的注释放开,在里面配置自己的Middleware

我们自定义的middleware写在自动生成的middlewares.py中

更简单的方法,使用插件fake-useragent

from fake_useragent import UserAgent
ua = UserAgent()
ua.ie
ua.firefox #而且每次都是不一样的随机的版本
ua.random #不同浏览器不同版本随机切换
settings:
from fake_useragent import UserAgent
DOWNLOADER_MIDDLEWARES = {
   'ArticleSpider.middlewares.ArticlespiderDownloaderMiddleware': 543,
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
}

可以设置RANDOM_UA_TYPE来制定浏览器或者random
RANDOM_UA_TYPE = "random"

middleware:
class RandomUserAgentMiddleware(object):
    #随机更换user-agent
    def __init__(self, crawler):
        super(RandomUserAgentMiddleware, self).__init__()
        # self.user_agent_list = crawler.settings.get("user_agent_list",[])
        self.ua = UserAgent()
        self.ua_type = crawler.settings.get("RANDOM_UA_TYPE", "random")

    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler)

    def process_request(self, request, spider):
        # request.headers.setdefault("User-Agent", self.ua.random)
        def get_ua():
            return getattr(self.ua, self.ua_type)
        request.headers.setdefault("User-Agent", get_ua())

用代理ip速度会比较慢,可以用自己的ip注意限速爬取

ip代理 可以用西刺http://www.xicidaili.com/

也是加在上面的process_request中

request.meta["proxy"] = "http://122.114.31.177:808"

但是一个ip是不够的 我们要设置一个ip代理池 随机获取使用

这里可以通过爬取西刺这个网站 获取到代理ip的信息使用

用脚本的方式写这个爬虫,如下:

import requests
from scrapy.selector import Selector
import MySQLdb

conn = MySQLdb.connect(host="127.0.0.1", user="root", passwd="1234", db="article", charset="utf8")
cursor = conn.cursor()

def crawl_ips():
    #爬取西刺的免费ip代理
    headers = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"}
    for i in range(10):
        re = requests.get("http://www.xicidaili.com/nn/{0}".format(i), headers=headers)

        selector = Selector(text=re.text)
        all_trs = selector.css("#ip_list tr")

        ip_list = []
        for tr in all_trs[1:]:
            speed_str = tr.css(".bar::attr(title)").extract()[0]
            if speed_str:
                speed = float(speed_str.split("秒")[0])
            all_texts = tr.css("td::text").extract()

            ip = all_texts[0]
            port = all_texts[1]
            proxy_type = all_texts[5]

            ip_list.append((ip, port, proxy_type, speed))

            print(all_texts)

        for ip_info in ip_list:
            cursor.execute(
                "insert into proxy_ip(ip, port, speed, proxy_type) VALUES ('{0}', '{1}', '{2}', 'HTTP')".format(
                    ip_info[0], ip_info[1], ip_info[3]
                )
            )
            conn.commit()

class GetIP(object):
    def delete_ip(self, ip):
        #从数据库中删除无效的ip
        delete_sql = "delete from proxy_ip where ip='{0}'".format(ip)
        cursor.execute(delete_sql)
        conn.commit()
        return True

    def judge_ip(self, ip, port):
        #判断ip是否可用
        http_url = "http://www.baidu.com"
        proxy_url = "http://{0}:{1}".format(ip, port)
        try:
            proxy_dict = {
                "http":proxy_url
            }
            response = requests.get(http_url,proxies=proxy_dict)
        except Exception as e:
            print("invalid ip and port")
            self.delete_ip(ip)
            return False
        else:
            code = response.status_code
            if code >= 200 and code <=300:
                print("effective ip")
                return True
            else:
                print("invalid ip and port")
                self.delete_ip(ip)
                return False


    def get_random_ip(self):
        #从数据库中随机获取一个可用的ip
        random_sql= """
            SELECT ip,port FROM proxy_ip ORDER BY RAND() LIMIT 1
        """
        result = cursor.execute(random_sql)
        for ip_info in cursor.fetchall():
            ip = ip_info[0]
            port = ip_info[1]
            judge_re = self.judge_ip(ip, port)
            if judge_re:
                return "http://{0}:{1}".format(ip, port)
            else:
                return self.get_random_ip()


# crawl_ips()
#注意这里的用法
if __name__ == "__main__":
    a = GetIP()
    b = a.get_random_ip()
    print (b)

middleware中编写获取ip代理:

from tools.crawl_xici_ip import GetIP
class RandomProxyMiddleware(object):
    #动态设置ip代理
    def process_request(self, request, spider):
        get_ip = GetIP()
        request.meta["proxy"] = get_ip.get_random_ip()

scrapy-proxies github上有 可以去上面看

免费的代理ip可能不稳定,如果有需要可以试试收费的
scrapy-crawlera github上有的

tor:洋葱网络 洋葱浏览器 经过包装达到隐藏ip效果

验证码识别方法

  • 编码实现(tesseract-ocr):识别率低
  • 在线打码:高 例:云打码
  • 人工打码:几乎就是人在操作。。。

其他防止被识别的技能:

禁用cookie (request就不会把我们的cookie带过去)(一般要登录的不禁用,不用登陆的禁用)
settings中:COOKIES_ENABLED = False
启用限速扩展 (前面已经说过了)
要先开启再设置值

AUTOTHROTTLE_ENABLED = TRUE
DOWNLOAD_DELAY = 10

给不用的spider适用不用的setting值

class LagouSpider(CrawlSpider):

    #这里的会覆盖settings里的
    custom_settings = {
        "COOKIES_ENABLED": True
    }

猜你喜欢

转载自blog.csdn.net/qq_24095055/article/details/86655524