【爬虫高阶】ip代理池的构建步骤详解及json数据的写入与读取(附源代码)

1. 代理ip网站的选择

这里以百度搜索“代理ip”为关键词,搜索结果中返回的第一个非广告信息作为爬取ip信息的网站,如下,该信息网址:快代理官方网址

在这里插入图片描述

2. ip信息的爬取

2.1 网页翻页的规律探索

一般选取前2-4页进行网页url规律的查找,如下

u2 = 'https://www.kuaidaili.com/free/inha/2/'
u3 = 'https://www.kuaidaili.com/free/inha/3/'
u4 = 'https://www.kuaidaili.com/free/inha/4/'

由此就可以找到翻页网址url的规律了, 除了最后的数字跟随着网页页数发生变化之外,其余的并没有发生改变

2.2 框架搭建

还是熟悉的感觉,进行常用库的导入,为了防止爬取的频率过快,引用time库进行程序间歇式爬取数据,基本上两个函数加上一个接口就可以完成框架的搭建。

其中接口提供的是要爬取的ip的页数(一页有20个ip信息),然后两个函数,第一个是解析页面的,第二个是获取ip信息的

import requests
from bs4 import BeautifulSoup
import time

headers = {
    'Referer': 'https://www.kuaidaili.com/free/inha/1/',
    'Cookie': '_ga=GA1.2.1075258978.1586877585; _gid=GA1.2.304073749.1587691875; ',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
} #这里的refer,cookie和header加上自己浏览器的即可

def get_ip(url):
    html = requests.get(url,headers)
    if html.status_code == 200:
        print('正在爬取中...')
        time.sleep(2)
        parse_html(html.text)
    else:
        print('Error',url)

def parse_html(text):
	pass
    
if __name__ == '__main__':
    num = eval(input('请输入要爬取的页数:'))
    for i in range(1,num + 1):
        url = f'https://www.kuaidaili.com/free/inha/{i}/'
        get_ip(url)

3. ip信息的爬取

刚刚框架已经搭建完成,主要的就是解析页面中内容的设计,如下

def parse_html(text):
    soup = BeautifulSoup(text,'lxml')
    ips = soup.select('#list tbody tr')
    for line in ips:
        ip = line.select_one('td').text
        port = line.select('td')[1].text
        print(f'Ip:{ip},Port:{port}')

→ 输出的结果为:(先进行第一页ip信息的爬取,进行程序试错)
在这里插入图片描述

4. 验证ip有效性

这里就是对框架进行功能函数的扩充,为了验证ip是否有效,可以封装一个测试函数,进行某一网站信息的爬取(这里以百度网站进行爬取验证,并设置反应时间为3s,如果3s内没有反应,则是无效)

#这几句代码是接在上面的print输出后面的,将ip和port组成可用的地址
#最后将地址加载到代理里面传入到验证ip函数中
address = f'http://{ip}:{port}'
proxies = {
    'http':address,
    'https':address
}
verify_ip(proxies)


def verify_ip(proxies):
    try:
        html = requests.get('http://www.baidu.com',proxies = proxies,timeout = 3)
        print(f'[SUCCESS]可用代理:{proxies}')
    except :
        print(f'[ERROR]代理不可用:{proxies}')

→ 输出的结果为:(返回的结果中是包含可以使用的ip信息的,虽然失效率很高,但是也是可以白嫖到的)
在这里插入图片描述

5. 将有效ip信息保存至本地

由上的输出可以发现,还是有可以使用的信息的,为了方便今后爬虫的调用,可以将有效信息保存在本地,因此可以封装一个函数,进行有效ip信息的追加储存,如下

#这条语句是要在 print(f'[SUCCESS]可用代理:{proxies}')后面,调用存储ip信息的函数
save_ip(proxies)

#封装函数
def save_ip(proxies):
    with open('ip_text.txt','a+') as f:
        f.write(str(proxies)+'\n')#写入文本的时候,要以字符串的方式写入
        print('\n[SUCCESS]代理已经写入文本!!!')

→ 输出的结果为:
在这里插入图片描述

6. 代理ip读取有效性检测

因为免费代理ip的时效性,爬取时有效的ip信息,当再次调用的时候,不一定生效,所以为了避免这种情况,可以在框架的基础上添加上读取代理ip信息的有效验证,这样再调取本地代理ip信息的时候就可以直接使用了

def read_txt():
    with open('ip_text.txt','r',encoding='utf-8') as f:
        contents = f.readlines()
        for content in contents:
            print(content) #这里输出的还是字符串类型,存入的是字符串,读取的自然也是           

→ 输出的结果为:(爬取5页的信息,最后返回的只有5个可以使用)
在这里插入图片描述
测试验证,如下,代码是接在上面的print语句之后的,注意一下,读取的信息是字符串,而传递到proxies参数上的应该是字典类型,所以这里可以使用eval函数,将字符串转化为字典类型

try:
    html = requests.get('http://www.baidu.com', proxies=eval(content), timeout=3)
    print('[SUCCESS]有效代理',content)
except:
    print('[ERROR]失效代理',content)

→ 输出的结果为:(经过一段时间后再测试,还有3条代理是至今可用的)
在这里插入图片描述

7. 全部代码

import requests
from bs4 import BeautifulSoup
import time

headers = {
    'Referer': 'https://www.kuaidaili.com/free/inha/1/',
    'Cookie': '_ga=GA1.2.1075258978.1586877585; _gid=GA1.2.304073749.1587691875; Hm_lvt_7ed65b1cc4b810e9fd37959c9bb51b31=1586877585,1587691875; channelid=0; sid=1587690934346679; Hm_lpvt_7ed65b1cc4b810e9fd37959c9bb51b31=1587692242',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}

def get_ip(url):
    html = requests.get(url,headers)
    if html.status_code == 200:
        print('正在爬取中...')
        time.sleep(2)
        parse_html(html.text)
    else:
        print('Error',url)

def parse_html(text):
    soup = BeautifulSoup(text,'lxml')
    ips = soup.select('#list tbody tr')
    for line in ips:
        ip = line.select_one('td').text
        port = line.select('td')[1].text
        print(f'[INFO]获取Ip:{ip},Port:{port}......')
        address = f'http://{ip}:{port}'
        proxies = {
            'http':address,
            'https':address
        }
        verify_ip(proxies)

def verify_ip(proxies):
    try:
        html = requests.get('http://www.baidu.com',proxies = proxies,timeout = 3)
        print(f'[SUCCESS]可用代理:{proxies}')
        save_ip(proxies)
    except :
        print(f'[ERROR]代理不可用:{proxies}')

def save_ip(proxies):
    with open('ip_text.txt','a+') as f:
        f.write(str(proxies)+'\n')
        print('\n[SUCCESS]代理已经写入文本!!!')

def read_txt():
    with open('ip_text.txt','r',encoding='utf-8') as f:
        contents = f.readlines()
        for content in contents:
            # print(content)
            try:
                html = requests.get('http://www.baidu.com', proxies=eval(content), timeout=3)
                print('[SUCCESS]有效代理',content)
            except:
                print('[ERROR]失效代理',content)

if __name__ == '__main__':
    num = eval(input('请输入要爬取的页数:'))
    for i in range(1,num + 1):
        url = f'https://www.kuaidaili.com/free/inha/{i}/'
        get_ip(url)
    # read_txt()
	#如果要验证读取代理ip的有效性,可以把read_text()语句前面的四行注释掉,调用read_text()函数即可

8. 拓展

如果觉得以字符串的形式保存代理ip信息后有需要以字符串形式的方式读取,最后使用还需转字典,过程太过复杂,可以直接将获取的address变量以字典的形式直接存储在本地,那么读取的时候自然也就是字典的格式,不需要再进行转化了,如下

8.1 json数据写入

# 写入json数据
def save_ip(proxies):
    # with open('ip_text.txt','a+') as f:
    #     f.write(str(proxies)+'\n')
    #     print('\n[SUCCESS]代理已经写入文本!!!')
    with open('ip_text.json','a+',encoding='utf-8') as f:
        d = json.dumps(proxies)
        f.write(d + '\n')
        print('\n[SUCCESS]代理已经写入文本!!!')

→ 输出的结果为:(还是爬取五页)
在这里插入图片描述

8.2 json数据读取

def read_txt():
    # with open('ip_text.txt','r',encoding='utf-8') as f:
    #     contents = f.readlines()
    #     for content in contents:
    #         print(content)
    with open('ip_text.json','r' , encoding='utf-8') as f:
        for line in f:
            try:
                content = json.loads(line.strip())
                #print(content)
                html = requests.get('http://www.baidu.com', proxies=content, timeout=3)
                print('[SUCCESS]有效代理',content)
            except:
                print('[ERROR]失效代理',content)

→ 输出的结果为:(经过一段时间测试后,只有一个有用了,而且最后一个网址还引发了报错)
在这里插入图片描述

原创文章 159 获赞 93 访问量 4万+

猜你喜欢

转载自blog.csdn.net/lys_828/article/details/105723698