Python之网络爬虫(验证码、代理IP、防反爬策略、封装一个抓取页面的函数)

文章目录

      • 一、使用tesseract做OCR验证码识别
      • 二、代理服务器设置
      • 三、反爬与防反爬
      • 四、封装一个抓取页面的函数

一、使用tesseract做OCR验证码识别

1、cookie, session的作用
用户曾经访问过个这个网站,我们需要在HTTP协议之外用一些额外的信息和技术来标识这个用户曾经来过为了让用户体验更好;所以我们的爬虫程序可以巧妙的利用这个漏洞来达到登录获取信息的效果。

2、安装tesseract
pip install pytesseract

3、测试tesseract
1)from pytesseract import *
2)然后,在captchaTest. py程序中有一张验证码的图片
3)去噪音,找出验证码的色彩;
4)背景色与前景色的区分;
5)提取出一个个字符;
6)使用余弦相似度来计算两个字符之间的相似,
https: L /blog. csdn. net /whi terbear/article/details .
7)得到当前字符最大概率匹配的样本集中的字

4、注意
验证码这一关是涉及机器学习方面的内容,里面的水很深,因此处理验证码时一定要考虑好时间成本。如果图像识别技术实在搞不定验证码这一关,可以选择使用打码平台,最终都无法解决,那也只能手动输入了。

5、打码平台运作的方式
1)首先在打码平台注册账号,获取到合法的Key, ID等信息;
2)使用这些Key, ID去调对方的API:读取文件成字节流,做一次Base64转码,去调API接口,返回结果;
3))到结果,进行下一-步操作;如果出错,根据返回结果来判断如果排错。

二、代理服务器设置

1、代理服务器:借助别人的手来完成访问,将自己的ip地址给伪装起来,爬虫时不会被服务器发现恶意访问

2、设置代理服务器IP:打开控制面板的Internet选项,点连接,设置,代理服务器,输入对应的地址和端口号(port)

3、IP和MAC地址的区别
HTTP数据包在传递过程,源地址和目标地址是不变的。填写的是IP地址,发包过程中经历各个路由器使用的是MAC地址,不同的路由器就有不同的物理地址,即MAC地址,因此这个MAC地址是不断变化的。

4、代理服务器使用方法

# 使用代理服务器来访问:ProxyHandler需要接受的是一个字典
import urllib.request

def use_http_proxy(proxy_addr, url):
    # 构造代理服务区的handler
    proxyH = urllib.request.ProxyHandler({"https":proxy_addr})
    #创建一个Http 的opener
    opener = urllib.request.build_opener(proxyH,
                                urllib.request.HTTPHandler)
    # 把构造出来的opener载入到全局的urllib里
    urllib.request.install_opener(opener)
    # 发起Http请求:设置超时为6秒(超过6秒没有反应就报错)
    res = urllib.request.urlopen(url,timeout=6)
    # 读取信息
    data = res.read().decode("utf-8")
    return data

if __name__ == "__main__":
    proxy_addr = "114.224.223.164:9999"  # 代理服务器
    data = use_http_proxy(proxy_addr, "https://www.sina.com.cn/")
    print(data)

三、反爬与防反爬

1、网站如何发现爬虫

  • 单一IP非常规的访问频次;
  • 单一IP非常规的数据流量;
  • 大量重复简单的网站浏览行为,只下载网页,没有后续的JS,CSS请求;
  • 通过一些陷阱来发现爬虫,例如一些通过CSS对用户隐藏的链接,只有爬虫才会访问。

2、网站一般如何进行反爬虫

  • 大量使用动态网页,是的爬虫的爬取难度增加,重要数据都拿不到,即使爬虫用了Web环境来渲染(内置浏览器),也会大大增加爬虫的负担和爬虫时间; (当采用动态加载的技术,对服务器的负担也会大大减轻)。
  • 基于流量的拒绝,开启带宽限制模块,限制每个IP最多连接数,最大带宽等。

3、如何发现自己被反爬了

  • 频繁验证码的出现
  • Unusual content delivery delay非常规的延时;。
  • Freguent response with HTTP 403,404, 301 or 50x error

4、防反爬策略
1)User-Agent 池
2)代理服务器池
3)CookieJar 等的管理
4)协议的细节考虑,如:需要大量的实践经验总结的。抓取数据时不处理CSS,JS等,nofollow属性,css 的display属性,探测陷阱
验证refer locator等。
5)使用分布式的多机策略,爬慢点,把爬虫放到访问频繁的主站IP子网下,比如教育网;
6)使用了规则来批量爬取,需对规则进行组合
7)验证码的处理:机器学习,图像识别
8)尽可能遵守Robots协议

四、封装一个抓取页面的函数

以下是完整代码,关于各个地方的详细说明都在注释中了。


# 库的导入
import logging
import sys
import random
from urllib import request
from urllib import error
from urllib import parse
import time

# 日志的写入
# 获取logger的实例
logger = logging.getLogger("testLogger")
# 指向logger的输出格式
formatter = logging.Formatter('%(asctime)s \t  %(levelname)s \t %(message)s')
# 文件,终端日志对象
file_handler = logging.FileHandler("testLogger2.log")
# 将文件日志按照刚刚设置的格式来写
file_handler.setFormatter(formatter)
console_handler = logging.StreamHandler(sys.stdout)
# 终端日志按照指定的格式来写
console_handler.setFormatter(formatter)
# 可以设置日志的级别:INFO高于DEBUG
logger.setLevel(logging.DEBUG)
# 把文件日志、终端日志,添加到logger日志处理器
logger.addHandler(file_handler)
logger.addHandler(console_handler)

# 代理服务器允许设置的范围
minRangeForProxy = 1
maxRangeForProxy = 10
minSleepTime = 1
maxSleepTime = 3

# 下载网页的函数大封装
def downloadHtml(url, headers=[],
                 proxy={}, useProxyRate=0,
                 timeout=None, decodeInfo="utf-8",
                 num_retries=5):
    """
    这是一个爬取网页数据的函数
    :param url:网页地址
    :param headers:请求头,包括User-Agent,Cookie,Host,Connection
    :param proxy:代理服务器的社会中
    :param timeout:超时设置,超过时间就报错
    :param decodeInfo:网页编码的指定
    :param num_retries:如果错误,重新尝试的次数
    :return:服务器返回错误状态码的处理,如果是400+则直接记录日志,如果是500+则重新跑几次downloadHtml函数
    """
    # 控制代理服务器的使用频率:若useProxyRate==0,则表示不使用代理服务器
    if random.randint(minRangeForProxy,
                      maxRangeForProxy) >= useProxyRate:
        proxy = None  # 就不使用代理服务器了
        print("No using proxy!")

    # 创建proxy handler
    proxy_handler = request.ProxyHandler(proxy)

    # 创建opener
    opener = request.build_opener(proxy_handler)

    # 把proxy_handler安装到urllib中
    request.install_opener(opener)

    # 设置http的request头信息
    opener.addheaders = headers

    # 发起请求
    html = None  # 设置一个初始值,如果成功了则替换获取到的html信息,否则则是一个空(也算有默认值)
    try:
        res = request.urlopen(url)  # 如果这里设置timeout,则是socket的超时设置
        html = res.read().decode(decodeInfo)
    # 抛出异常,则将异常写入日志
    except UnicodeDecodeError:
        logger.error("UnicodeDecodeError")
    # 可能还会有其他类型的异常,比如状态码
    except error.URLError or error.HTTPError as e:
        logger.error("Download Error")
        # 对于300+的错误是跳转一般不需要额外处理

        # 如果是400+的状态码,403禁止访问,是客户端访问的问题,则直接记录日志
        logger.error("Client Error!")
        return html

        # 如果是500+的状态码,则获取错误的状态码500+(服务器的问题),使用递归重新再跑几次
        if num_retries > 0:
            # 在尝试之前先休息一下,缓一缓:随机休息1-3秒
            time.sleep(random.randint(minSleepTime, maxSleepTime))
            if hasattr(e, 'code') and 500 <= e.code < 600:
                # 出现这类访问错误,则重再跑一次函数
                html = downloadHtml(url, headers,
                     proxy, useProxyRate,
                     timeout, decodeInfo, num_retries-1)

    return html

# 参数的设定
headers = [("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Safari/537.36",)]
proxy_addr = {"http": "114.224.223.164:9999"}

# 调用函数
print(downloadHtml("http://www.baidu.com/",headers=headers,
             proxy=proxy_addr))

# 不使用日志后,将日志移除
logger.removeHandler(file_handler)
logger.removeHandler(console_handler)

你可能感兴趣的:(Python进阶者)