前言

在网络爬虫中,有些网站会设置反爬虫措施,服务器会检测某个IP在单位时间内的请求次数,如果超过了这个阈值,就会直接拒绝服务,返回一些错误信息,例如 403 Forbidden,“您的IP访问频率过高”这样的提示,这就是IP被封禁了,这种情况下就需要进行IP伪装。

代理的基本原理

代理实际上指的是代理服务器(proxy server),它的功能是代理网络用户去去的网络信息,是网络信息的中转站,一般情况下,请求访问网站时,是先发送请求给Web服务器,Web服务器再把响应传回给我们,如下图:

如果设置了代理服务器,实际上是在本机和服务器之间建立了一个桥梁,此时本机不是直接向Web服务器发起请求,而是向代理服务器发出请求,请求会发送给代理服务器,然后由代理服务器再发送给Web服务器,接着由代理服务器再把Web服务器返回的响应转发给本机,图解如下,这样同样可以正常访问网页,但这个过程中Web服务器识别出的真实IP就不再是我们本机的IP了,就成功实现了IP伪装,这就是代理的基本原理。

代理的作用

  • 突破自身IP访问限制,访问一些平时不能访问的站点
  • 访问一些单位或团体内部资源
  • 提高访问速度:通常代理服务器都设置一个较大的硬盘缓冲区,当有外界信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时,则直接由缓冲区中取出信息,传给用户,以提高访问速度
  • 隐藏真实IP,当作防火墙保护自身网络安全,在爬虫中可以防止自身的IP被封锁

代理分类

1. 根据协议区分

  • FTP 代理服务器:主要用于访问FTP服务器,一般有上传、下载以及缓存功能,端口一般为 21、2121等
  • HTTP 代理服务器:主要用于访问网页,一般有内容过滤和缓存功能,端口一般为 80、8080、3128等
  • SSL/TLS 代理:主要用于访问加密网站,一般有 SSL 或 TLS 加密功能(最高支持128位加密强度),端口一般为 443
  • RTSP 代理:主要用于访问Real流媒体服务器,一般有缓存功能,端口一般为 554
  • Telnet 代理:主要用于 telnet 远程控制(黑客入侵计算机时常用于隐藏身份),端口一般为 23
  • POP3/SMTP 代理:主要用于 POP3/SMTP 方式收发右键,一般有缓存功能,端口一般为 110/25
  • SOCKS 代理:只是单纯传递数据包,不关心具体协议和用法,所以速度很快,一般有缓存功能,端口一般为 1080 。SOCKS 代理协议又分为 SOCK4 和 SOCK5,SOCK4 只支持TCP,而后者支持 TCP 和 UDP,还支持各种身份验证机制、服务器端域名解析等。

2. 根据匿名程度区分

  • 高度匿名代理:会将数据包原封不动的转发,在服务端看来就好像真的是一个普通客户端在访问,而记录的IP是代理服务器的IP
  • 普通匿名代理:会在数据包上做一些改动,服务端上有可能发现这是个代理服务器,也有一定几率追查到客户端的真实IP。代理服务器通常会加入的HTTP头有 HTTP_VIA 和  HTTP_X_FORWORD_FOR
  • 透明代理:不但改动了数据包,还会告诉服务器客户端的真实IP。这种代理除了能用缓存技术提高浏览速度,能用内容过滤提高安全性之外,并无其他显著作用,最常见的例子是内网中的硬件防火墙
  • 间谍代理:指组织或个人创建的用于记录用户传输的数据,然后进行研究、监控等目的的地理服务器

常见代理设置

  • 使用网上的免费代理:最好使用高匿代理,这里将在下面爬取代理网站中所有代理
  • 使用付费代理服务:付费代理会比免费代理更为稳定,效果更好,按需求选择
  • ADSL 拨号:拨一次号换一次 IP,稳定性高

爬取代理网站IP

1. 定位所需网页元素节点,获取内容

以云代理网站为例,网站地址:云代理 - 高品质http代理ip供应平台/每天分享大量免费代理IP

这里我选择的是用Xpath解析库进行匹配爬取,在使用之前,需要确保安装好了 lxml 库,lxml 是 Python 的一个解析库,支持 HTML 和 XML 解析,支持 Xpath 解析方式,而且解析效率非常高,安装方式为:

pip3 install lxml

如果没报错,则安装成功,若出现报错,例如缺少 libxml2 库等信息,可以采用 wheel 方式安装,推荐链接:https://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml,下载对应的 wheel 文件,找到本地安装 Python 版本和系统对应的 lxml 版本,例如 Windows 64 位、python 3.6,就选择如下方式下载到本地:

pip3 install lxml-3.8.0-cp36-cp36m-win_amd64.whl

如图可以看出,我们所需要的信息全都在 <tr> 标签中的 <td> 里,这就能写出 Xpath 表达式:

# 将 html 字符串转换为 _ELEMENT 对象
html = etree.HTML(html)
result = html.xpath("//div[@id='list']//tr/td/text()")

可以通过浏览器插件 Xpath Helper 来验证是否正确,相关插件的安装及使用方式,可以参考博文:

selenium中如何配置使用浏览器插件 及 xpath-helper、chropath下载方式_Yy_Rose的博客-CSDN博客_xpath 插件

2. 连接 MySQL 数据库,创建表格

import pymysql# 获取数据库连接
db = pymysql.connect(host='localhost', user='root', passwd='123456', port=3306, db='proxy')
# 获取游标
cursor = db.cursor()
# 若无 proxy 数据库可执行如下操作
# cursor.execute("create database proxy default character set utf8")
# 删除之前创建的表格,不然新的数据会直接添加在旧数据之后,造成数据冗余
cursor.execute("drop table proxy_pool")
create_sql = "create table if not exists proxy_pool(" \"代理IP地址 varchar(255) not null," \"端口 int not null," \"匿名度 text not null," \"类型 varchar(255) not null," \"支持 varchar(255) not null," \"位置 text not null," \"响应速度 text not null," \"最后验证时间 varchar(255) not null)engine=innodb default charset=utf8;"
cursor.execute(create_sql)

3. 写入本地 txt

proxy_dir = 'proxy_pool.txt'
# 以追加模式写入
with open(proxy_dir, 'a', encoding='utf-8') as f:# json.dumps序列化时对中文默认使用的ascii编码,想输出真正的中文需要指定ensure_ascii=Falsef.write(json.dumps(content, ensure_ascii=False) + '\n')

4. 测试获取到的IP是否可用

代理IP样式为:代理IP地址 :端口,所以需要先获取相关内容,存入标准代理样式列表:

ip_and_port.append(proxy_infos[0].text.strip() + ':' + proxy_infos[1].text.strip())

以请求访问百度为例,传入获取到的代理IP,若网站返回状态码为 200 则说明此代理IP有效,将有效的代理IP存入相应的可用代理列表中并输出显示,若出现其他情况则判断该代理IP无效,并显示该代理IP。

def ip_test(ip_and_port_list, usable_ip_list):url = "https://www.baidu.com/"try:for ip in ip_and_port_list:try:response = requests.get(url, proxy={'https': ip},headers=headers, timeout=0.5)if response.status_code == 200:usable_ip_list.append(ip)print("该代理ip有效:" + ip)else:print("该代理ip无效:" + ip)except:print("该代理ip无效:" + ip)except:return None

完整代码

# @Author : Yy_Rose
import requests
from lxml import etree
import json
from requests.exceptions import RequestException
import time
import pymysql# 获取数据库连接
db = pymysql.connect(host='localhost', user='root', passwd='123456', port=3306, db='proxy')
# 获取游标
cursor = db.cursor()
# 若无 proxy 数据库可执行如下操作
# cursor.execute("create database proxy default character set utf8")
# 删除之前创建的表格,不然新的数据会直接添加在旧数据之后,造成数据冗余
cursor.execute("drop table proxy_pool")
create_sql = "create table if not exists proxy_pool(" \"代理IP地址 varchar(255) not null," \"端口 int not null," \"匿名度 text not null," \"类型 varchar(255) not null," \"支持 varchar(255) not null," \"位置 text not null," \"响应速度 text not null," \"最后验证时间 varchar(255) not null)engine=innodb default charset=utf8;"
# 执行数据库操作
cursor.execute(create_sql)# 构建请求头
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64)'' AppleWebKit/537.36 (KHTML, like Gecko)'' Chrome/86.0.4240.198 Safari/537.36','Cookie': 'Hm_lvt_c4dd741ab3585e047d56cf99ebbbe102=1640671968,''1641362375;'' Hm_lpvt_c4dd741ab3585e047d56cf99ebbbe102=1641362386'
}# 获取 HTTPResponse 类型的对象
def get_one_page(url):try:response = requests.get(url, headers=headers)if response.status_code == 200:# 编码response.encoding = 'gbk'return response.textreturn Noneexcept RequestException:return None# 解析获取内容
def parse_one_page(proxy_pool, html, ip_and_port):# 将 html 字符串转换为 _ELEMENT 对象content = etree.HTML(html)# 第一行为 th 标签内容,故从第二行开始tr_cnotent_list = content.xpath("//div[@id='list']//tr")[1:]for proxy_infos in tr_cnotent_list:# strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列proxy_pool.append([proxy_infos[0].text.strip(),proxy_infos[1].text.strip(),proxy_infos[2].text.strip(),proxy_infos[3].text.strip(),proxy_infos[4].text.strip(),proxy_infos[5].text.strip(),proxy_infos[6].text.strip(),proxy_infos[7].text.strip()])ip_and_port.append(proxy_infos[0].text.strip() + ':' + proxy_infos[1].text.strip())ip = proxy_infos[0].text.strip()port = proxy_infos[1].text.strip()anonymity = proxy_infos[2].text.strip()ip_type = proxy_infos[3].text.strip()support_type = proxy_infos[4].text.strip()position = proxy_infos[5].text.strip()response_speed = proxy_infos[6].text.strip()verify_time = proxy_infos[7].text.strip()# 将获取到的数据插入到数据库中insert_into = ("INSERT INTO proxy_pool(代理IP地址,端口,匿名度,类型,支持,位置,响应速度,最后验证时间)""VALUES(%s,%s,%s,%s,%s,%s,%s,%s);")data_into = (ip, port, anonymity, ip_type, support_type, position,response_speed,verify_time)cursor.execute(insert_into, data_into)# 将 insert 语句提交给数据库db.commit()# 写入本地 txt
def wirte_to_txt(content):proxy_dir = 'proxy_pool.txt'# 以追加模式写入with open(proxy_dir, 'a', encoding='utf-8') as f:# json.dumps序列化时对中文默认使用的ascii编码,想输出真正的中文需要指定ensure_ascii=Falsef.write(json.dumps(content, ensure_ascii=False) + '\n')# 打印内容到控制台
def print_list(proxy_list):for i in range(10):print(proxy_list[i])wirte_to_txt(proxy_list[i])# 测试IP是否可用
def ip_test(ip_and_port_list, usable_ip_list):url = "https://www.baidu.com/"try:for ip in ip_and_port_list:try:response = requests.get(url, proxy={'https': ip},headers=headers, timeout=0.5)if response.status_code == 200:usable_ip_list.append(ip)print("该代理ip有效:" + ip)else:print("该代理ip无效:" + ip)except:print("该代理ip无效:" + ip)except:return Nonedef main(offset):# 分页爬取url = 'http://www.ip3366.net/?stype=1&page=' + str(offset)html = get_one_page(url)proxy_pool = []usable_ip = []ip_port = []parse_one_page(proxy_pool, html, ip_port)print("以下为查询到的数据:")print_list(proxy_pool)print('=' * 50)ip_test(ip_port, usable_ip)print('=' * 50)print("有效的代理ip为:")# 判断列表是否为空if usable_ip:for usable in usable_ip:print(usable, end=' ')else:print(f"很遗憾,第{offset}页的代理IP全都无效")print('=' * 50)if __name__ == '__main__':num = int(input("请输出想查询多少页ip:"))# 共10页,100条记录,range()为左闭右开for page in range(1, num + 1):main(offset=page)time.sleep(2)

控制台打印:

代理IP测试:

本地 txt:

数据库效果:

写项目过程中的报错

pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'get/post支持 varchar(255) not null,位置 text not null,响应速度 text not ' at line 1")

原因:创建表格的字段名与MySQL关键字冲突,get/post 支持改为支持即可

TypeError: not all arguments converted during string formatting

原因:并非所有参数都在字符串格式化期间转换

insert_into = ("INSERT INTO proxy_pool(代理IP地址,端口,匿名度,类型,支持,位置,响应速度,最后验证时间)""VALUES(?,?,?,?,?,?,?,?);")

分析可能性一:

一开始使用的是 ?占位符, 其可使用参数的位置,标识变量,用于变量传值,支持和最后验证时间列不止一个元素,?无法完全匹配,导致参数数量不对应

更改为 %s 就好了,%s 表示 str(),字符串可以包含空格、特殊字符,能一一匹配到完整元素

insert_into = ("INSERT INTO proxy_pool(代理IP地址,端口,匿名度,类型,支持,位置,响应速度,最后验证时间)""VALUES(%s,%s,%s,%s,%s,%s,%s,%s);")

分析可能性二:

import sqlite3

在SQLite数据库中,可以直接使用第一种方法插入一条或多条数据,经测试成功插入

import pymysql

在MySQL数据库中,不支持第一种插入方法

pymysql.err.InterfaceError: (0, '')

原因:数据库连接在创建表格后就关闭了,导致无法进行数据库操作,插入数据操作时报错

pymysql.err.DataError: (1366, "Incorrect string value: '\\xE9\\xAB\\x98\\xE5\\x8C\\xBF...' for column '匿名度' at row 1")

原因:创建数据库时未将字符集设置为 utf-8 格式,更改为 utf8 -- UTF-8 Unicode 即可,以下为之前导致报错的样式:

总结

免费的代理 IP 大部分都是无效的,不稳定的,以上为代理的相关知识及如何爬取代理网站代理 IP 列表的相关介绍,欢迎评论指正交流~

代理的基本原理 及用Xpath爬取代理网站IP列表 测试并存入数据库相关推荐

  1. 爬虫基础练习: 基于 java + Jsoup + xpath 爬取51job网站

    最基本的网页爬虫练习 爬取51jb网站,并将数据写入Excel中 需要导入jsoup包和POI相关包 JSoup简介 jsoup是一款Java的HTML解析器,主要用来对HTML解析, 可通过DOM, ...

  2. 利用node爬取王者荣耀英雄信息,并存入数据库

    抓取 一.新建一个文件夹 文件夹不要是中文 二.下载第三方模块 cmd进入文件夹地址,输入:npm init -y进行初始化 输入npm i crawler mysql-ithm下载爬虫和node-o ...

  3. 爬取学校官网信息公告并存入数据库

    前段时间做了爬取学校信息并展示的小软件,爬取内容包括学校官网.教学管理系统.招生就业信息等,其中用到了QueryList库.翻页爬虫,定时爬虫,插入数据库等 不熟系QueryList的可以看一下我的这 ...

  4. 【JAVA爬虫】爬取猫眼电影TOP100并将数据存入数据库

    前几天的简单写了个利用JSOUP进行JAVA爬虫,里面有谈到后续版本会更新数据库操作,所以这次来更新了. 版本更新 此次的版本里数据爬取部分新增了[电影主演-star]和[电影评分-score]部分, ...

  5. 每日10行代码31:爬取人民日报一日的所有文章并存入数据库

    今天又增加了存入数据库的功能,至此,爬取人民日报的项目已经结束,下一步我将跟另一篇文章的博主比较下代码,从他那学一些有用的东西. import requests import re from bs4 ...

  6. 为什么用python扒取出来的数据为空列表_如何解决python xpath爬取页面得到空列表(语法都对的情况下)...

    引言: 很多网页呈现给我们的静态页面,但是实际上是由服务器端的动态页面生成的.再加上网站设有反爬虫机制,所以抓取到的页面不一定和源码相同. 所以!!从源码里copy xpath,不一定能取到数据! 实 ...

  7. xpath 爬取某网站图片

    效果图请自行脑补,此处不做展示(狗头保命) from lxml import etree import requests import osif __name__ == '__main__':url ...

  8. python 爬取微博实时热搜,并存入数据库实例

    刚学python没几天,打算用paython爬去微博热搜数据试验一下,但是发现微博热搜是动态数据,网页源码并不能直接获取想要的数据,network里也并不能找到相关内容,这时重新查看网页源码,发现有类 ...

  9. Python爬虫简单运用爬取代理IP

    功能1: 爬取西拉ip代理官网上的代理ip 环境:python3.8+pycharm 库:requests,lxml 浏览器:谷歌 IP地址:http://www.xiladaili.com/gaon ...

最新文章

  1. PMP®考试是什么机构
  2. 46W 奖金池等你来战!微众银行第三届金融科技高校技术大赛火热报名中!
  3. 史上最强 NIO 框架,没有之一!!!
  4. 计算机网络 tcp 阻塞,读书笔记:计算机网络第7章:阻塞控制
  5. 图片优化之下一代图片格式WebP和AVIF
  6. mysql用户创建,及授权
  7. 2017.10.25
  8. P1420 最长连号(python3实现)
  9. 【Elasticsearch】Elasticsearch底层系列之Shard Allocation机制
  10. 糟糕!原来你的电脑就是这样被木马远控了
  11. 机器学习面试-数学基础
  12. Winform 表格布局
  13. VassistX番茄助手使用技巧
  14. Mac软件下载提示:“已损坏,无法打开”解决办法
  15. 对TMS320F28335存储空间的理解
  16. ppt滚动动画随机选题
  17. 简历里计算机能力,简历上计算机能力怎么写
  18. Linq 语法(转载)
  19. 【无法完成更新 正在撤销更改 请不要关闭你的计算机】更新失败解决方案
  20. dba招生_DBA工商管理博士正在招生

热门文章

  1. MATLB|基于燃料电池混合动力汽车双层凸优化
  2. db2sql报错代码大全
  3. 二〇二三-三-二十九
  4. 浅谈浏览器标准模式与怪异模式、文档类型
  5. 泉州计算机中专学校,2021泉州中专学校排名榜
  6. 魅蓝note2android8,魅蓝Note2支持扩展储存卡吗?支持多大的储存卡?
  7. CC2540 内存结构分析
  8. 智慧穿戴装置带动医疗大数据发展
  9. Microsoft Office Excel 不能访问文件
  10. RK3229添加两个遥控器用户码