前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >selenium 和 IP代理池

selenium 和 IP代理池

作者头像
全栈程序员站长
发布2022-08-15 21:23:08
1.4K0
发布2022-08-15 21:23:08
举报

大家好,又见面了,我是你们的朋友全栈君。

3.1 selenium

selenium: Selenium 是一个自动化测试工具,利用它可以 驱动浏览器 执行特定的动作,如点击、下拉等操作(模拟浏览器操作) 同时还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬

Selenium支持非常多的浏览器,如 Chrome、Firefox、PhantomJS等

浏览器对象的初始化 并将其赋值为 browser 对象。接下来,我们要做的就是调用 browser 对象,让其执行各个动作以模拟浏览器操作 eg:要使用google浏览器

代码语言:javascript
复制
——browser = webdriver.Chrome()

访问页面:get方法 eg:

代码语言:javascript
复制
from selenium import webdriver
 #声明
browser = webdriver.Chrome()
#请求网页
browser.get('https://www.taobao.com')
#打印源码
print(browser.page_source)
#关闭网页
browser.close()
#效果:弹出Chrome,自动访问tb,打印源码,关闭页面

查找节点(比如 找到账号输入框): 1:单个节点 返回:WebElement 类型 find_element_by_id find_element_by_name find_element_by_xpath find_element_by_link_text find_element_by_partial_link_text find_element_by_tag_name find_element_by_class_name find_element_by_css_selector 变式: find_element(By.a,b)——参数a输入属性,参数b输入值

代码语言:javascript
复制
 find_element_by_id(id)
 ==
 find_element(By.ID, id)

2:多个节点(淘宝左边所有的导航栏条目): 如果我们用 find_element()方法,只能获取匹配的第一个节点 如果用 find_elements()方法,返回:列表类型,包含所有符合要求的节点,列表中的每个节点是 WebElement 类型

find_elements_by_id find_elements_by_name find_elements_by_xpath find_elements_by_link_text find_elements_by_partial_link_text find_elements_by_tag_name find_elements_by_class_name find_elements_by_css_selector

节点交互(模拟人的操作—有特定对象): 输入文字—— send_keys()方法 清空文字—— clear()方法 点击按钮—— click()方法

动作链(模拟人的操作—无特定对象): 没有特定的执行对象,比如鼠标拖曳、键盘按键等 用另一种方式来执行——动作链 http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.common.action_chains

获取节点信息: Selenium 提供了选择节点的方法,返回的是 WebElement 类型 它也有相关的方法和属性来直接提取节点信息,如属性、文本等。 这样的话,我们就可以不用通过解析源代码来提取信息了,方便 属性值: get_attribute() 方法来获取节点的属性,但是其前提是先选中这个节点 通过get_attribute()方法,然后传入想要获取的属性名,就可以得到它的值 文本: 每个 WebElement 节点都有 text 属性,直接调用这个属性就可以得到节点内部的文本信息 ——相当于 Beautiful Soup 的 get_text()方法

WebElement 节点还有一些其他属性 比如 id 属性可以获取节点 id location 属性可以获取该节点在页面中的相对位置 tag_ name 属性可以获取标签名称 size 属性可以获取节点的大小,也就是宽高

繁琐一点的话,就用page_source 属性获取网页的源代码,接着使用解析库

切换Frame(子页面): switch_to.frame()方法 Selenium在一个 页面中,完成 对这个页面 的操作。在父页面无法对子Frame操作

延时等待: 确保节点已经加载出来——在 Selenium 中,get()方法会在网页框架加载结束后 结束执行,此时可能并不是浏览器完全加载完成的页面 1:隐式 换句话说,当查找节点 而节点并没有立即出现的时候,隐式等待 将等待一段时间再查找DOM,默认的时间是0 implicitly_ wait() 2:显式 隐式等待的效果并没有那么好,因为我们只规定了一个 固定时间,而页面的加载时间会受到网络条件的影响

显式——它指定一个等待条件(要查找的节点),然后指定一个最长等待时间。 如果在规定时间内满足 等待条件(加载出来了这个节点),就返回要查找的节点; 如果到了规定时间还没有 等待条件(没有加载出该节点),则抛出超时异常 eg:

代码语言:javascript
复制
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(browser, 10)
input = wait.until(EC.presence_of_element_located((By.ID, 'q')))
#首先引入WebDriverWait这个对象,指定最长等待时间,然后调用它的until()方法,传入要等待条件expected_conditions。比如,这里传入了presence_of_element_located这个条件,代表节点出现的意思,其参数是节点的定位元组,也就是ID为q的节点搜索框

更多等待条件的参数及用法,参考官方文档:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions 前进后退: back()方法后退, forward()方法前进 eg:

代码语言:javascript
复制
import time
from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
browser.get('https://www.taobao.com/')
browser.get('https://www.python.org/')

browser.back()
time.sleep(1)
browser.forward()
browser.close()

Cookies: 对 Cookies 进行操作 例如获取、添加、删除 Cookies 等 get_cookies() ——获取 add_cookie()——添加 delete_all_cookies() ——删除所有的 Cookies

选项卡: execute_ script()方法 switch_ to_ window()——切换选项卡

异常处理: try except 语句——捕获异常,放置程序遇到异常而中断

实战:selenium模拟登陆163(126)邮箱

代码语言:javascript
复制
# 登陆,打开网页页面,加载成功后,找到账号密码框,输入账号密码,点击登陆
# 对应
#访问页面。查找输入框等节点。输入cookes等信息,模拟点击(交互)

from selenium import webdriver
import time

url = 'https://www.126.com/'
def open_page(url):
    browser = webdriver.Chrome()
    browser.get('https://www.126.com/') #打开网页
    time.sleep(2)
    #以上代码OK
    browser.switch_to.frame(0)#关键
    
    #找到账号框,密码框,登陆按钮。然后输入信息
    card = browser.find_element_by_name('email')#账号框
    card.send_keys('dengzhanh')
    
    password = browser.find_element_by_name('password') #密码框
    password.send_keys('*******')
    
    login = browser.find_element_by_id('dologin')#登陆按钮
    login.click()

def main():
    open_page(url)
    
if __name__=='__main__':
    main()

问题: 1—browser.switch_to.frame(0) 是在同一界面选择一个子界面么?()内的参数怎么填? 2—账号密码框 在源码中,如何快捷地找到其 属性?

3.2 IP ——参考:网络爬虫开发实战 IP(代理): 网站为了防止被爬取,会有反爬机制 服务器会检测某个IP在单位时间内的请求次数,如果超过了这个阈值,就会直接拒绝服务,返回一些错误信息——可以称为封IP

应对IP被封的问题: 修改请求头,模拟浏览器(把你当做是个人)访问 采用代理IP 并轮换 设置访问时间间隔(同样是模拟人,因为人需要暂停一会)

代理:在本机 和 服务器 之间搭桥 本机不直接发送请求,通过桥(代理服务器)发送请求 web代理 通过桥 返回 响应

请求库的代理设置方法 1:requests 的代理设置:只需要构造代理字典,然后通过 proxies 数即可,而不需要重新构建 pener

代码语言:javascript
复制
proxies = {
'http': 'http ://'+ proxy,
'https': 'https://'+ proxy, 

如果需要 验证,下面的代码输入两个部分即可 proxy= ‘username:password@代理 ’

使用 SOCKS5 代理(需要安装SOCKS库) 1:

代码语言:javascript
复制
proxies = {
'http':'socks5 ://'+ proxy,
'http': 'socks5: // '+ proxy
}

2:全局设置

代码语言:javascript
复制
import requests
import socks
import socket
socks.set_default_proxy(socks . 50CKS5,’127.0 .0.1 ’, 9742)
socket.socket = socks.socksocket 

2:Selenium代理设置: 以Chrome为例

代码语言:javascript
复制
from selenium import webdriver

proxy= 127.0.0.1:9743
chrome_ options = webdriver.ChromeOptions ()
chrome_options.add_argument('…proxy-server=http://'+ proxy)

browser = webdriver.Chro e(chrome_options=chrome_options)
browser.get(’ http://httpbin.org/get ' ) 

若是 认证代理: 需要在本地创建一个 manifest.json 配置文件 和 background.js 脚本来设置认证代理 运行代码之后本地会生成一个 proxy auth __plugin.zip 文件来保存当前配置

代理池: 不是所有的代理都能用,所以要进行 筛选,提出不可用代理,保留可用代理 ∴ 建立代理池 设计代理的基本思路:(代理池的目标) 1:存储模块(存代理)——负责存储抓取下来的代理。首先要保证代理不重复,要标识代理的可用情况,还要动态实时处理每个代理。 所以一种比较高效方便的存储方式就是使用 Redis的Sorted Set,即有序集合

2:获取模块(抓代理)——需要定时在各大代理网站抓取代理。代理可以是免费公开代理也可以是付费代理,代理的形式都是 IP 加端口,此模块尽量从不同来源获取,尽量抓取高匿代理,抓取成功之后将 可用代理 保存到数据库中

3:检测模块(能用否)——需要定时检测数据库中的代理。这里需要设置一个检测链接,最好是爬取哪个网站就检测哪个网站,这样更加有针对性,如果要做一个通用型的代理,那可以设置百度等链 接来检测。 另外,我们需要标识每一个代理的状态,如设置分数标识,100分代表可用,分数越少代表越不可用。——检测一次,如果代理可用,我们可以将分数标识立即设置为100分,也可以在原基础上加1分;如果代理不可用,可以将分数标识减1分,当分数减到一定阈值后,代理就直接从数据库移除。通过这样的标识分数,我们就可以辨别代理的可用情况,选用的时候会更有针对性

4:接口模块(拿出来)——需要用 API 来提供对外服务的接口。其实我们可以直接连接数据库采取对应的数据,但是这样就需要知道数据库的连接信息,并且要配置连接。 而比较安全和方便的方式就是提供一个 Web API 接口,我们通过访问接口即可拿到可用代理。另外,由于可用代理可能有多个,那么我们可以 设置一个 随机返回 某个可用代理 的接口,这样就能保证 每个可用代理都可以取到,实现 负载均衡。

根据以上,设计代理池架构

在这里插入图片描述
在这里插入图片描述

注: 存储模块——使用 Redis 有序集合,用来做代理的 去重 和 状态标识,同时它也是中心模块和基 础模块,将其他模块串联起来 获取模块——定时从代理网站获取代理,将获取的代理传递给存储模块,并保存到数据库 检测模块——定时通过存储模块获取所有代理,并对代理进行检测,根据不同的检测结果对代理 设置不同的标识 接口模块——通过 WebAPI 提供服务接口,接口通过连接数据库并通过Web 形式返回可用的代理

4个模块的实现

1:存储模块 这里我们使用 Redis 的有序集合,集合的每一个元素都是不重复的 对于代理池来说,集合的元素就变成了 个个代理,也就是 IP 加端口的形式, eg:60.207.237.111 :8888 ,这样的一个代理就是集合的一个元素。 另外,有序集合的每一个元素都有一个分数字段,分数是可以重复的,可以是浮点数类,也可以是整数类型。 该集合会根据每一个元素的分数对集合进行排序,数值小的排在前面,数值大的排在后面,这样就可以实现集合元素的排序了。 对于代理池来说,这个分数可以作为判断一个代理是否可用的标志, 100 为最高分,代表最可用,0为最低分,代表最不可用。 如果要获取可用代理,可以从代理池中随机获取分数最高的代理,注意是随机,这样可以保证每个可用代理都会被调用到 引入分数机制 定义常量,比如:分数(最大最小初始)、Redis的连接信息(地址、端口、密码)、有序集合的键名(获取) 定义类,用于操作Redis的有序集合,其中定义一些方法,用于处理集合中的元素。

获取模块: 定义一个 Crawler 来从各大网站抓取代理 将获取代理的每个方法统一定义为以Crawl 开头,这样扩展的时候只需要添加Crawl 开头的方法即可。 这些方法都定义成了生成器,通过 yield返回代理。程序首先获取网页,然后用解析,解析出 IP加端口的形式的代理 然后返回 然后定义了一个 get_proxies ()方法,将所有以 crawl 开头的方法调用一遍,获取每个方法返回的代理 并 组合成列表形式返回 依次通过 get_proxies方法调用,得到各个方法抓取到的代理,然后再利用 Redi sClien的add方法加入数据库,这样获取模块的工作就完成了 检测模决: 使用异步请求库aiohttp 接口模块: 代理池可以作为一个独立服务运行,我们最好增加一个接口模块,并以 WebAPI的形式暴露可用代理——获取代理只需要请求接口即可 调度模块: 调度模块就是调用以上所定义的 3个模块,将这 个模块通过多进程的形式运行起来 实战:

代码语言:javascript
复制
import requests
from bs4 import BeautifulSoup
from collections import OrderedDict
from threading import Thread
from datetime import datetime
start_time = datetime.now()

def get_xici_proxy(url,headers):
    response = requests.get(url, headers=headers).content
    res = response.decode('utf-8')
    soup = BeautifulSoup(res, 'lxml')
    tag_tr_all = soup.find_all('tr')

    info_names = tag_tr_all[0].get_text().strip().split('\n')
    # global proxy_list
    t_list = []
    for tag_tr in tag_tr_all[1:]:  
        tag_td = tag_tr.find_all('td')#
        try:
            country = tag_td[0].img['alt'] 
        except TypeError:#
            country = 'None'
        try:
            ip_info_list = [td.get_text(strip=True) for td in tag_td[1:]] 
            ip_info_list.insert(0,country)
            ip_info_dict = OrderedDict(zip(info_names,ip_info_list))
            t = Thread(target =check_proxy,args=(ip_info_dict,))
            t_list.append(t)
        except Exception as e:
            print("登录错误",e)
    for i in range(len(tag_tr_all[1:])):
        t_list[i].start()
    for i in range(len(tag_tr_all[1:])):
        t_list[i].join()

def check_proxy(info):
    proxy = {info['类型'].lower():r"{}://{}:{}".format(info['类型'].lower(),info['IP地址'],info['端口']),}
    try:
        response1 = requests.get(r"http://httpbin.org/get",proxies=proxy,timeout=10)
        print(response1.status_code)
        if response1.status_code==200:
            info['proxy'] = proxy
            proxy_list.append(info)
    except Exception as e:
        pass#
if __name__ == "__main__":
    url = r"https://www.xicidaili.com/nn"
    headers = {
        'User-Agent': "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"
    }
    proxy_list = [] 
    get_xici_proxy(url,headers)

    print("有效代理数:",len(proxy_list))
    print("第二个代理地址:",proxy_list[1].get('proxy'))
    print("第二个代理地址类型:",proxy_list[1].get('类型'))

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/134465.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022年5月2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档