欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

python爬虫基础(6:IP代理池)

程序员文章站 2022-05-30 22:49:52
...

除了上篇文章(https://blog.csdn.net/Jeeson_Z/article/details/81409730)提到的 UA检测 

反爬措施还有 IP检测

IP检测

有些网站当检测到同一个IP连续快速访问时,可能会把这个IP拉黑,*掉

爬虫的速度贼快,有极大的可能被网站*

IP代理

相当于一个 中介

你把请求给他,他帮你安排不同的IP访问,相当于是很多不同的IP在访问,从而避免被*

这个 中介 按质量不同有免费的和收费的

作为案例选取 免费的 66免费代理网http://www.66ip.cn/

python爬虫基础(6:IP代理池)

例如选用上表第一条 39.135.35.16:80 作为代理(代理得加上 端口号

依然访问直接放回请求头的工具网站:http://httpbin.org/get

# 导入requests请求库
import requests


# 要访问的网址
url = 'http://httpbin.org/get'
# 填入代理IP和端口
proxy = '39.135.35.16:80'
# 构造完整的代理链接(url)
proxies = {
    # HTTP协议的完整url
    # 格式:协议+IP+目录
    'http': 'http://' + proxy,
    # HTTPS协议简单来说就是HTTP协议的安全版
    'https': 'https://' + proxy,
}
# proxies参数设置代理
rsp = requests.get(url, proxies=proxies)
# rsp = requests.get(url)
print(rsp.text)

结果如****意:IP可能会不能用,如果不能用,则换一个就好)

python爬虫基础(6:IP代理池)

 

维护IP代理池

一个 IP 代理池首先肯定需要很多 IP 地址,所以第一步是要将代理网站给出的 IP 爬取下来

并不是所有的 IP 都能用,所以要先 测试一下

测试完后 保存到数据库

然后提供一个 接口 方便获取

注意:有些第一次测试不能用但不代表以后不可用,所以我们 为每个IP设置一个分数,代表可用程度

           1. 每个 IP 初始分数为 10

           2. 如果能用,则为设置为 100

           3. 如果不能用,则分数 -1 

           4. 如果分数为 0 ,则移除

连接数据库

自己先建一个用于存放 IP 的数据库

然后连接到数据库并创建操作游标

# 导入数据库驱动模块
import pymysql


# 编写数据库部分

# 一句话连接数据库
db = pymysql.connect(host='localhost', user='root', password='123456xun', db='csdn', charset='utf8mb4')
# 利用cursor()方法创建一个操作游标
cursor = db.cursor()

# 编写所需要的sql语句
sql_insert = 'INSERT INTO proxy(ip, port, score) VALUES (%s, %s, %s)'
sql_delete = 'DELETE FROM proxy WHERE score=0'
sql_select = 'SELECT ip,port FROM proxy WHERE score=100'

既然要爬取,就要写爬虫,老规矩

我们按照 下载源码解析数据保存数据 三大步来进行爬取

对应的工具分别是用于访问下载的  requests库,用于解析的 BeautifulSoup库、用于保存的 pymysql驱动模块

爬取函数

# 导入requests请求库
import requests
# 导入解析库
from  bs4 import BeautifulSoup


# 编写爬取部分
def crawl_66():
    # 代理网站的地址的格式
    # 根据观察url,发现各省的代理IP页面由数字控制
    # 所以我们先用占位符{}代替这个数字的位置
    url = 'http://www.66ip.cn/areaindex_{}/1.html'
    # 定义用于存放IP的列表
    ipes = []
    # 共34个省
    for page in range(35):
        # 先填占位符生成一个省的url
        url = url.format(page)
        # get()方法访问,得到一个Response对象
        rsp = requests.get(url)
        # Response对象的text属性得到源码
        text = rsp.text
        # 用BeautifulSoup()方法将源码生成能被解析的lxml格式文件
        soup = BeautifulSoup(text, 'lxml')
        # 用find()找放置IP的表
        table = soup.find(name='table', attrs={'border': '2px'})
        # 用find_all()找到所以的IP
        ip_list = table.find_all(name='tr')
        # 循环遍历每个IP
        for addr in ip_list:
            # 观察源码发现第一个tr里的内容不是IP,所以跳过
            if addr == ip_list[0]:
                continue
            # 获取IP
            ip = addr.find_all(name='td')[0].string
            # 获取端口
            port = addr.find_all(name='td')[1].string
            # 设置初始分数
            init_score = 10
            # 利用IP和端口拼接一个代理url
            proxy_url = 'http://' + ip + ':' + port
            # 调用检测模块,获取分数
            score = test(proxy_url, init_score)
            # 用一个字典保存一个IP的各种信息
            ip_addr = {
                'ip': ip,
                'port': port,
                'score': score,
            }
            # 将此条IP添加到IP列表
            ipes.append(ip_addr)
    # 将IP列表返回
    return ipes

上面模块调用了检测函数

下面就来写 检测函数 ,以尝试访问百度为例

# 编写检测部分

# 接受代理url和分值
def test(url, init_score):
    # 如果此条url的分数都被减到0了,就删除它
    if init_score == 0:
        cursor.execute(sql_delete)
        db.commit()
    # 以访问百度作为测试
    test_url = 'https://www.baidu.com/'
    # 编写代理url
    proxy = {
        'http': url,
    }
    # proxies参数填写代理
    rsp = requests.get(test_url, proxies=proxy)
    # 判断返回码是否等于200,200表示成功
    if rsp.status_code == 200:
        # 成功就把分数设置为100
        score = 100
    else:
        # 否则分数减一
        score = init_score - 1
    # 返回分数
    return score

以上代码每次都用requests访问,效率十分低,有兴趣的朋友可以自个琢磨怎么优化

当IP、端口、分数都设置好了以后

就该 保存到数据库 

# 导入数据库驱动模块
import pymysql


# 编写储存部分
def save_ip():
    # 从爬取函数获取代理IP信息
    ipes = crawl_66()
    # 遍历每条信息
    for ip in ipes:
        # 赋值并执行mysql保存语句
        cursor.execute(sql_insert, (ip['ip'], ip['port'], ip['score']))
        # 提交操作
        db.commit()
    # 关闭数据库
    db.close()

 

保存完毕之后,爬虫要怎么使用呢?

这就需要编写一个 接口 

# 接口部分
def api():
    # 定义一个用于存放IP的列表
    proxies = []
    # 执行mysql查询语句
    cursor.execute(sql_select)
    # fetchall()方法获取查询结果,返回一个元组
    result = cursor.fetchall()
    # 遍历每条结果
    for addr in result:
        # 获取IP
        ip = addr[0]
        # 获取端口
        port = addr[1]
        # 拼接出代理IP的url
        proxy = {
            'http': 'http://' + ip + ':' + port,
            'https': 'https://' + ip + ':' + port,
        }
        # 将此条代理添加到列表
        proxies.append(proxy)
    # 返回列表
    return proxies

 

这里作为案例就不编写爬虫来调用它了

编写 代码入口

# 代码入口
if __name__ == '__main__':
    # 从储存函数开始
    save_ip()

全部代码

# 导入requests请求库
import requests
# 导入解析库
from  bs4 import BeautifulSoup
# 导入数据库驱动模块
import pymysql


# 编写数据库部分
# 一句话连接数据库
db = pymysql.connect(host='localhost', user='root', password='123456xun', db='csdn', charset='utf8mb4')
# 利用cursor()方法创建一个操作游标
cursor = db.cursor()
# 编写所需要的sql语句
sql_insert = 'INSERT INTO proxy(ip, port, score) VALUES (%s, %s, %s)'
sql_delete = 'DELETE FROM proxy WHERE score=0'
sql_select = 'SELECT ip,port FROM proxy WHERE score=100'



# 编写检测部分
# 接受代理url和分值
def test(url, init_score):
    # 如果此条url的分数都被减到0了,就删除它
    if init_score == 0:
        cursor.execute(sql_delete)
        db.commit()
    # 以访问百度作为测试
    test_url = 'https://www.baidu.com/'
    # 编写代理url
    proxy = {
        'http': url,
    }
    # proxies参数填写代理
    rsp = requests.get(test_url, proxies=proxy)
    # 判断返回码是否等于200,200表示成功
    if rsp.status_code == 200:
        # 成功就把分数设置为100
        score = 100
    else:
        # 否则分数减一
        score = init_score - 1
    # 返回分数
    return score


# 编写爬取部分
def crawl_66():
    # 代理网站的地址的格式
    # 根据观察url,发现各省的代理IP页面由数字控制
    # 所以我们先用占位符{}代替这个数字的位置
    url = 'http://www.66ip.cn/areaindex_{}/1.html'
    # 定义用于存放IP的列表
    ipes = []
    # 共34个省
    for page in range(35):
        # 先填占位符生成一个省的url
        url = url.format(page)
        # get()方法访问,得到一个Response对象
        rsp = requests.get(url)
        # Response对象的text属性得到源码
        text = rsp.text
        # 用BeautifulSoup()方法将源码生成能被解析的lxml格式文件
        soup = BeautifulSoup(text, 'lxml')
        # 用find()找放置IP的表
        table = soup.find(name='table', attrs={'border': '2px'})
        # 用find_all()找到所以的IP
        ip_list = table.find_all(name='tr')
        # 循环遍历每个IP
        for addr in ip_list:
            # 观察源码发现第一个tr里的内容不是IP,所以跳过
            if addr == ip_list[0]:
                continue
            # 获取IP
            ip = addr.find_all(name='td')[0].string
            # 获取端口
            port = addr.find_all(name='td')[1].string
            # 设置初始分数
            init_score = 10
            # 利用IP和端口拼接一个代理url
            proxy_url = 'http://' + ip + ':' + port
            # 调用检测模块,获取分数
            score = test(proxy_url, init_score)
            # 用一个字典保存一个IP的各种信息
            ip_addr = {
                'ip': ip,
                'port': port,
                'score': score,
            }
            # 将此条IP添加到IP列表
            ipes.append(ip_addr)
    # 将IP列表返回
    return ipes


# 编写储存部分
def save_ip():
    # 从爬取函数获取代理IP信息
    ipes = crawl_66()
    # 遍历每条信息
    for ip in ipes:
        # 赋值并执行mysql保存语句
        cursor.execute(sql_insert, (ip['ip'], ip['port'], ip['score']))
        # 提交操作
        db.commit()
    # 关闭数据库
    db.close()


# 接口部分
def api():
    # 定义一个用于存放IP的列表
    proxies = []
    # 执行mysql查询语句
    cursor.execute(sql_select)
    # fetchall()方法获取查询结果,返回一个元组
    result = cursor.fetchall()
    # 遍历每条结果
    for addr in result:
        # 获取IP
        ip = addr[0]
        # 获取端口
        port = addr[1]
        # 拼接出代理IP的url
        proxy = {
            'http': 'http://' + ip + ':' + port,
            'https': 'https://' + ip + ':' + port,
        }
        # 将此条代理添加到列表
        proxies.append(proxy)
    # 返回列表
    return proxies


# 代码入口
if __name__ == '__main__':
    # 从储存函数开始
    save_ip()

github 地址:https://github.com/JeesonZhang/pythonspider/blob/master/v06.py