精华内容
参与话题
问答
  • Spring Boot 2.x: 爬取ip代理池

    万次阅读 2020-06-20 23:35:06
    Spring Boot 2.x: 爬取ip代理池入库 概述 因为爬虫的进阶阶段,最基本的就是要用到ip代理池,因为单个代理请求频繁,会被ban掉,所以要备一个代理池,用来请求使用 技术栈 HttpClient Spring Boot 2.3.1 JDK 1.8 ...

    Spring Boot 2.x: 爬取ip代理池入库

    在这里插入图片描述

    概述

    因为爬虫的进阶阶段,最基本的就是要用到ip代理池,因为单个代理请求频繁,会被ban掉,所以要备一个代理池,用来请求使用

    技术栈

    • HttpClient
    • Spring Boot 2.3.1
    • JDK 1.8

    快速创建Spring Boot项目

    访问 https://start.spring.io/ 生成一个初始项目

    初始项目
    我们需要去请求接口,所以需要一个Web依赖

    添加Web依赖
    点击Generate,会下载一个zip的项目压缩包

    导入Spring Boot项目

    解压之后记得复制下demo文件夹放的路径

    先用IDE编辑 pom.xml 文件,在下图红框上面加入下述代码

    可以切换下载依赖的源为国内阿里源
    切换下载依赖的源为国内阿里源

    <repositories>
            <!--阿里云主仓库,代理了maven central和jcenter仓库-->
            <repository>
                <id>aliyun</id>
                <name>aliyun</name>
                <url>https://maven.aliyun.com/repository/public</url>
                <releases>
                    <enabled>true</enabled>
                </releases>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
            </repository>
            <!--阿里云代理Spring 官方仓库-->
            <repository>
                <id>spring-milestones</id>
                <name>Spring Milestones</name>
                <url>https://maven.aliyun.com/repository/spring</url>
                <releases>
                    <enabled>true</enabled>
                </releases>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
            </repository>
        </repositories>
        <pluginRepositories>
            <!--阿里云代理Spring 插件仓库-->
            <pluginRepository>
                <id>spring-plugin</id>
                <name>spring-plugin</name>
                <url>https://maven.aliyun.com/repository/spring-plugin</url>
                <releases>
                    <enabled>true</enabled>
                </releases>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
            </pluginRepository>
        </pluginRepositories>
    

    下面是导入流程:

    IDEA里点击File -> Open -> 粘贴刚刚的项目文件夹路径 -> 找到pom.xml双击
    -> Open as Peoject -> 等待Maven加载完毕,看不明白看下图
    找到pom文件打开
    Open as Project,之后等待Maven加载完毕即可

    pom.xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.3.1.RELEASE</version>
    		<relativePath/> <!-- lookup parent from repository -->
    	</parent>
    	<groupId>com.github.gleans</groupId>
    	<artifactId>SpringBoot-ProxyPool</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<name>SpringBoot-ProxyPool</name>
    	<description>Demo project for Spring Boot</description>
    
    	<properties>
    		<java.version>1.8</java.version>
    		<httpclient.version>4.5.12</httpclient.version>
    		<jsonp.version>1.13.1</jsonp.version>
    		<knife4j.version>2.0.3</knife4j.version>
    		<lombok.version>1.18.12</lombok.version>
    		<mysql.version>8.0.19</mysql.version>
    	</properties>
    
    	<dependencies>
    		<dependency>
    			<groupId>org.apache.httpcomponents</groupId>
    			<artifactId>httpclient</artifactId>
    			<version>${httpclient.version}</version>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>org.projectlombok</groupId>
    			<artifactId>lombok</artifactId>
    			<version>${lombok.version}</version>
    			<scope>provided</scope>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-test</artifactId>
    			<scope>test</scope>
    			<exclusions>
    				<exclusion>
    					<groupId>org.junit.vintage</groupId>
    					<artifactId>junit-vintage-engine</artifactId>
    				</exclusion>
    			</exclusions>
    		</dependency>
    		<dependency>
    			<groupId>com.github.xiaoymin</groupId>
    			<artifactId>knife4j-spring-boot-starter</artifactId>
    			<version>${knife4j.version}</version>
    		</dependency>
    		<dependency>
    			<groupId>org.jsoup</groupId>
    			<artifactId>jsoup</artifactId>
    			<version>${jsonp.version}</version>
    		</dependency>
    		<dependency>
    			<groupId>mysql</groupId>
    			<artifactId>mysql-connector-java</artifactId>
    			<version>${mysql.version}</version>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-data-jpa</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-thymeleaf</artifactId>
    		</dependency>
    	</dependencies>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    			</plugin>
    		</plugins>
    	</build>
    	<repositories>
    		<!--阿里云主仓库,代理了maven central和jcenter仓库-->
    		<repository>
    			<id>aliyun</id>
    			<name>aliyun</name>
    			<url>https://maven.aliyun.com/repository/public</url>
    			<releases>
    				<enabled>true</enabled>
    			</releases>
    			<snapshots>
    				<enabled>false</enabled>
    			</snapshots>
    		</repository>
    		<!--阿里云代理Spring 官方仓库-->
    		<repository>
    			<id>spring-milestones</id>
    			<name>Spring Milestones</name>
    			<url>https://maven.aliyun.com/repository/spring</url>
    			<releases>
    				<enabled>true</enabled>
    			</releases>
    			<snapshots>
    				<enabled>false</enabled>
    			</snapshots>
    		</repository>
    	</repositories>
    	<pluginRepositories>
    		<!--阿里云代理Spring 插件仓库-->
    		<pluginRepository>
    			<id>spring-plugin</id>
    			<name>spring-plugin</name>
    			<url>https://maven.aliyun.com/repository/spring-plugin</url>
    			<releases>
    				<enabled>true</enabled>
    			</releases>
    			<snapshots>
    				<enabled>false</enabled>
    			</snapshots>
    		</pluginRepository>
    	</pluginRepositories>
    </project>
    
    

    新建ip实体对象

    package com.github.gleans.ekko.model;
    
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.experimental.Accessors;
    
    import javax.persistence.Entity;
    import javax.persistence.Id;
    
    @Data
    @Entity(name = "ip_data")
    @NoArgsConstructor
    @Accessors(chain = true)
    public class IPData {
    
        @Id
        @ApiModelProperty(value = "编号")
        private Long ipNo;
    
        @ApiModelProperty(value = "国家")
        private String country;
    
        @ApiModelProperty(value = "IP地址")
        private String ipAddress;
    
        @ApiModelProperty(value = "端口")
        private Integer port;
    
        @ApiModelProperty(value = "服务器地址")
        private String serverAddress;
    
        @ApiModelProperty(value = "是否匿名")
        private String anonymous;
    
        @ApiModelProperty(value = "类型")
        private String type;
    
        @ApiModelProperty(value = "速度")
        private String speed;
    
        @ApiModelProperty(value = "连接时间")
        private String connTime;
    
        @ApiModelProperty(value = "存活时间")
        private String survivalTime;
    
        @ApiModelProperty(value = "验证时间")
        private String postTime;
    }
    

    主要的业务类

    IPServiceImpl.java

    package com.github.gleans.ekko.service.impl;
    
    import com.github.gleans.ekko.model.IPData;
    import com.github.gleans.ekko.service.IPService;
    import com.github.gleans.ekko.utils.HttpCustom;
    import lombok.extern.slf4j.Slf4j;
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.select.Elements;
    import org.springframework.stereotype.Service;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Objects;
    import java.util.stream.Collectors;
    
    @Slf4j
    @Service
    public class IPServiceImpl implements IPService {
    
    
        @Override
        public List<IPData> getIpList() {
            String html = HttpCustom.getIpStore("https://www.xicidaili.com/nn/1", null, null);
            //将html解析成DOM结构
            Document document = Jsoup.parse(html);
    
            //提取所需要的数据
            Elements trs = document.select("table[id=ip_list]").select("tbody").select("tr");
    
            if (null == trs || trs.size() == 0) {
                return new ArrayList<>();
            }
    
            return trs.stream()
                    .map(tr -> {
                        Elements trd = tr.select("td");
                        if (trd != null && trd.size() > 0) {
                            String country = tr.select("td").get(0).text();
                            String ipAddress = tr.select("td").get(1).text();
                            Integer port = Integer.valueOf(tr.select("td").get(2).text());
                            String serverAddress = tr.select("td").get(3).text();
                            String anonymous = tr.select("td").get(4).text();
                            String ipType = tr.select("td").get(5).text();
                            String speed = tr.select("td").get(6).select("div[class=bar]").attr("title");
    
                            return new IPData().setIpAddress(ipAddress)
                                    .setPort(port).setType(ipType)
                                    .setCountry(country).setSpeed(speed)
                                    .setAnonymous(anonymous).setServerAddress(serverAddress);
                        } else {
                            return null;
                        }
    
                    }).filter(Objects::nonNull).collect(Collectors.toList());
        }
    }
    

    上面代码核心有参考:https://github.com/dhengyi/ip-proxy-pools-regularly

    封装请求类

    package com.github.gleans.ekko.utils;
    
    import org.apache.http.HttpHost;
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.util.EntityUtils;
    
    import java.io.IOException;
    import java.nio.charset.StandardCharsets;
    
    public class HttpCustom {
    
        private final static int CONNECT_TIMEOUT = 3000;
        private final static int SOCKET_TIMEOUT = 3000;
    
        /**
         * 获取网页信息
         *
         * @param url
         * @param ip
         * @param port
         */
        public static String getIpStore(String url, String ip, Integer port) {
    
            String resBody = "";
            CloseableHttpClient httpClient = HttpClients.createDefault();
    
            RequestConfig.Builder configBuilder = RequestConfig
                    .custom()
                    .setConnectTimeout(CONNECT_TIMEOUT)
                    .setSocketTimeout(SOCKET_TIMEOUT);
            if (ip != null && port != null) {
                HttpHost proxy = new HttpHost(ip, port);
                configBuilder.setProxy(proxy);
            }
            RequestConfig config = configBuilder.build();
    
            HttpGet httpGet = new HttpGet(url);
            httpGet.setConfig(config);
    
            httpGet.setHeader("Pragma", "no-cache");
            httpGet.setHeader("Connection", "keep-alive");
            httpGet.setHeader("Host", "www.xicidaili.com");
            httpGet.setHeader("Cache-Control", "no-cache");
            httpGet.setHeader("Upgrade-Insecure-Requests", "1");
            httpGet.setHeader("Accept-Language", "zh-CN,zh;q=0.8");
            httpGet.setHeader("Accept-Encoding", "gzip, deflate, sdch");
            httpGet.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
            httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36");
    
            try {
                //客户端执行httpGet方法,返回响应
                CloseableHttpResponse httpResponse = httpClient.execute(httpGet);
    
                //得到服务响应状态码
                if (httpResponse.getStatusLine().getStatusCode() == 200) {
                    resBody = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8);
                }
    
                httpResponse.close();
                httpClient.close();
            } catch (IOException e) {
                resBody = null;
            }
    
            return resBody;
        }
    
    }
    

    applicat.yml配置文件

    spring:
      datasource:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/big-data?characterEncoding=utf-8
          username: root
          password: root
      jpa:
        open-in-view: true
        database-platform: org.hibernate.dialect.H2Dialect
        # spring.jpa.show-sql=true 配置在日志中打印出执行的 SQL 语句信息。
        show-sql: true
        # 配置指明在程序启动的时候要删除并且创建实体类对应的表。
        # create 这个参数很危险,因为他会把对应的表删除掉然后重建。所以千万不要在生成环境中使用。只有在测试环境中,一开始初始化数据库结构的时候才能使用一次。
        # ddl-auto:create----每次运行该程序,没有表格会新建表格,表内有数据会清空
        # ddl-auto:create-drop----每次程序结束的时候会清空表
        # ddl-auto:update----每次运行程序,没有表格会新建表格,表内有数据不会清空,只会更新(推荐)
        # ddl-auto:validate----运行程序会校验数据与数据库的字段类型是否相同,不同会报错
        hibernate.ddl-auto: update
    

    前端显示

    技术栈

    • vue
    • element-ui
    • html5

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <!-- 引入样式 -->
        <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    </head>
    <body>
    
    <div id="app">
        <h1>{{ message }}</h1>
        是否重新抓取
        <el-switch
                v-model="isRefresh">
        </el-switch>
        <br>
        <!--    <template>-->
        <el-table
                :data="tableData"
                border
                style="width: 100%">
            <el-table-column
                    fixed
                    prop="ipAddress"
                    label="IP地址"
                    width="150">
            </el-table-column>
            <el-table-column
                    prop="port"
                    label="端口"
                    width="120">
            </el-table-column>
            <el-table-column
                    prop="serverAddress"
                    label="服务器地址"
                    width="120">
            </el-table-column>
            <el-table-column
                    prop="speed"
                    label="速度"
                    width="120">
            </el-table-column>
            <el-table-column
                    prop="type"
                    label="请求方式"
                    width="300">
            </el-table-column>
            <el-table-column
                    prop="anonymous"
                    label="匿名类型"
                    width="120">
            </el-table-column>
            <el-table-column
                    label="操作">
                    <el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button>
                    <el-button type="text" size="small">编辑</el-button>
            </el-table-column>
        </el-table>
        <!--    </template>-->
    </div>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <!-- 引入组件库 -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            methods: {
                getTableData() {
                    let _this = this;
                    // 为给定 ID 的 user 创建请求
                    axios.get('ip/list')
                        .then(function (response) {
                            console.log(response);
                            _this.tableData = response.data.data
                        })
                        .catch(function (error) {
                            console.log(error);
                        });
                }
            },
            created() {
                this.getTableData()
            },
            data: {
                message: 'ip池子代理',
                tableData: [],
                isRefresh: true
            }
        });
    </script>
    </body>
    </html>
    

    效果图

    启动之后。访问http://127.0.0.1:8080/index

    在这里插入图片描述

    TODO

    • 数据入库,防止一直调取人家接口(待实现)
    • 缓存,防止一直查询数据库(待实现)
    • 数据库去重,去除无效数据(待实现)
    • 页面可修改,查询列表(待实现)

    源码地址

    https://github.com/Gleans/SpringBootLearn/tree/master/SpringBoot-ProxyPool

    • 有问题关注公众号《Java Pro》私信我
    • 或者在CSDN私信我(不一定看得到)
    展开全文
  • proxybroker获取免费IP代理

    python利用proxybroker构建爬虫免费IP代理池

    大纲

    前言

    写爬虫的小伙伴可能遇到过这种情况:

    正当悠闲地喝着咖啡,满意地看着屏幕上的那一行行如流水般被爬下来的数据时,突然一个Error弹出,提示抓不到数据了...

    然后你反复检查,确信自己代码莫得问题之后,发现居然连浏览器也无法正常访问网页了...

    难道是网站被我爬瘫痪了?

    厉害

    然后你用手机浏览所爬网站,惊奇地发现居然能访问!

    才原来我的IP被网站给封了,拒绝了我的访问

    尴尬

    这时只能用IP代理来应对禁IP反爬策略了,但是网上高速稳定的代理IP大多都收费,看了看皱皱的钱包后,一个大胆的想法冒出

    我要白嫖!

    啥是IP代理?假如你现在17岁未成年,理想一点的情况会是,你去商店买烟,老板告诉你未成年不能买烟,并拒绝了你的购买,这叫被服务器拒绝访问;

    但是你不服气啊,于是你找来你20岁的哥哥,叫他去商店老板那帮你买包烟,然后再给你,这就叫IP代理。

    ProxyBroker简介

    ProxyBroker是一个开源软件,它从各种不同的IP代理网站中抓来公开的代理IP,并实时地检查代理IP的可用性,以供使用。

    所以可以说ProxyBroker是一个集成了爬虫技术的开源软件。

    ProxyBroker安装

    你可以通过pip来安装ProxyBroker

    pip install proxybroker

    也可以直接从Github下载最新版本的ProxyBroker

    pip install -U git+https://github.com/constverum/ProxyBroker.git

    在终端使用ProxyBroker

    安装成功后,你可以在终端中使用命令proxybroker

    proxybroker_usage

    proxybroker主要有三个子命令

    find子命令

    find子命令用于查找并检查公开的代理IP,换言之它会列出所有经测试可用的代理IP

    下列是find子命令的常用选项:

    选项 作用 可选值 示例
    --types 指定代理的类型 HTTP,HTTPS,SOCKS4,SOCKS5,CONNECT:80,CONNECT:25 --types HTTP HTTPS
    --lvl 指定代理的匿名级别 Transparent,Anonymous,High --lvl High
    --strict,-s 严格保证代理的类型与匿名级别等于指定的值 只要加上就表示启用严格模式 --strict
    --countries COUNTRIES,-c COUNTRIES 指定代理IP的所属国家 US,CN... -c CN
    --limit LIMIT, -l LIMIT 指定获取的条数 正整数即可 -l 5
    --outfile OUTFILE, -o OUTFILE 将找到的代理保存到文件中 文件路径 --outfile ./proxies.txt
    --format FORMAT, -f FORMAT 指定输出的格式,默认值为default default,json -f json
    --post 用post请求检查IP的可用性,默认是用get方式 只要加上就表示启用post请求检查 --post
    --show-stats 是否打印详细统计信息 只要加上就表示启用打印统计信息 --show-stats

    比如查找10条HTTP代理

    proxybroker find --types HTTP -l 10

    proxy_demo

    你可以将选项的示例值加上,自己尝试一下

    grab子命令

    grab子命令有点像find的简易版,它只进行查找,并不检查抓来IP的可用性

    下列是grab子命令的所有选项:

    选项 作用 可选值 示例
    --countries COUNTRIES,-c COUNTRIES 指定代理IP的所属国家 US,CN... -c CN
    --limit LIMIT, -l LIMIT 指定获取的条数 正整数即可 -l 5
    --outfile OUTFILE, -o OUTFILE 将找到的代理保存到文件中 文件路径 --outfile ./proxies.txt
    --format FORMAT, -f FORMAT 指定输出的格式,默认值为default default,json -f json
    --show-stats 是否打印详细统计信息 只要加上就表示启用打印统计信息 --show-stats

    可以看到它有的选项,find子命令都有,所以它是find的阉割版

    比如查找5条来自中国的代理,并将它保存至文件中

    proxybroker grab -c CN -o ./proxies.txt -l 5

    proxy_demo2

    serve子命令

    serve子命令用于搭建一个本地代理服务器,它可以分发你的请求至不同的IP代理中

    下列是serve子命令的常用选项:

    选项 作用 可选值 示例
    --host HOST 指定服务器的地址,默认是127.0.0.1 你本机的IP --host localhost
    --port PORT 指定服务器的端口,默认是8888 你本机可用的端口 --port 5000
    --max-tries SRV_MAX_TRIES 设置处理请求的最大重试次数 正整数 --max-tries 3
    --min-req-proxy MIN_REQ_PROXY 设置每个IP处理请求的最小次数 正整数 --min-req-proxy 3
    --http-allowed-codes HTTP_ALLOWED_CODES 设置允许代理返回的响应码 响应的状态码 --http-allowed-codes 302
    --max-error-rate MAX_ERROR_RATE 设置最大允许请求的异常率,例如0.5是50% 0~1 --max-error-rate 0.3
    --max-resp-time SECONDS 设置响应的最大允许秒数,默认是8秒 秒数 --max-resp-time 20
    --prefer-connect 如果可以的话,是否使用CONNECT方法 只要加上就表示使用 --prefer-connect
    --backlog BACKLOG 设置连接队列的最大值 正整数即可 --backlog 10
    - - - -
    --types 指定代理的类型 HTTP,HTTPS,SOCKS4,SOCKS5,CONNECT:80,CONNECT:25 --types HTTP HTTPS
    --lvl 指定代理的匿名级别 Transparent,Anonymous,High --lvl High
    --strict,-s 严格保证代理的类型与匿名级别等于指定的值 只要加上就表示启用严格模式 --strict
    --countries COUNTRIES,-c COUNTRIES 指定代理IP的所属国家 US,CN... -c CN
    --limit LIMIT, -l LIMIT 指定代理池的工作IP条数 正整数即可 -l 5

    serve子命令搭建代理服务器,相当于把我们本机变成中间商再中间商

    比如在地址为localhost,端口为5000,搭起高匿名代理服务器

    proxybroker serve --host localhost --port 5000 --types HTTP --lvl High

    proxy_serve

    然后先通过curl命令不使用代理访问一下http://httpbin.org/get这个地址,查看一下该网站显示我们的IP是多少

    curl http://httpbin.org/get

    curl_without_proxy

    再使用curl命令通过我们刚搭起的代理服务器访问一下,看看网站显示的IP是否有变化

    curl --proxy http://localhost:5000 http://httpbin.org/get

    curl_with_proxy

    在代码中使用ProxyBroker

    你可以通过proxybroker serve子命令搭起代理服务器,然后在发起请求时使用该代理,这种方法适用于几乎所有的编程语言

    requests库使用代理

    先serve搭起代理服务器

    proxybroker serve --host localhost --port 5000 --types HTTP --lvl High

    然后通过requests库设置代理

    import requests
    
    proxies = {
        "http": "http://localhost:5000",
        "https": "http://localhost:5000"
    }
    
    res = requests.get('http://httpbin.org/get', proxies=proxies)
    
    print(res.json())

    效果如下

    proxy_requests_demo

    scrapy库使用代理

    还是先serve搭起代理服务器,代码还是和上面一样

    在终端中,通过scrapy startproject新建一个爬虫项目,然后进入该项目目录里

    scrapy startproject proxy_demo
    cd proxy_demo

    通过scrapy genspider新建一个爬虫,名为proxy_spider_demo,域名为httpbin.org

    scrapy genspider proxy_spider_demo httpbin.org

    然后将下列代码粘贴至刚刚新建的爬虫中

    import json
    import scrapy
    # from scrapy.downloadermiddlewares.httpproxy import HttpProxyMiddleware
    
    
    class ProxySpiderDemoSpider(scrapy.Spider):
        name = 'proxy_spider_demo'
        allowed_domains = ['httpbin.org']
        # start_urls = ['http://httpbin.org/']
    
        def start_requests(self):
            meta = dict(proxy='http://localhost:5000')
            # 请求三次该网址,查看IP是否不同
            for _ in range(3):
                # 得加上dont_filter=True,否则第2、3个请求将被dupefilter过滤
                # 请求可以通过meta携带代理服务器地址,与HttpProxyMiddleware下载器中间件配合达到代理请求的目的
                yield scrapy.Request('http://httpbin.org/get', dont_filter=True, meta=meta, callback=self.parse)
    
        def parse(self, response):
            json_body = json.loads(response.text)
            print('当前请求的IP为:', json_body['origin'])
    

    在项目根目录处进入终端,通过scrapy crawl命令运行爬虫,这里加上了--nolog选项是为了专注于print的输出

    scrapy crawl --nolog proxy_spider_demo

    效果如下

    proxy_scrapy_demo

    python异步获取代理IP

    如果不希望通过serve子命令,直接在python代码中使用代理IP,可以通过asyncio来异步获取代理IP

    直接上代码

    import asyncio
    from proxybroker import Broker
    
    async def view_proxy(proxies_queue):
        while True:
            proxy = await proxies_queue.get()
            
            if proxy is None:
                print('done...')
                break
                
            print(proxy)
    
    # 异步队列
    proxies_queue = asyncio.Queue()
    
    broker = Broker(proxies_queue)
    
    tasks = asyncio.gather(
        # 使用grab子命令获取3条IP
        broker.grab(limit=3),
        view_proxy(proxies_queue))
    
    loop = asyncio.get_event_loop()
    _ = loop.run_until_complete(tasks)

    proxy_asyncio_demo

    获取到代理IP后,你可以通过aiohttp异步HTTP库或requests库来使用它们

    总结

    你可以利用ProxyBroker库来白嫖免费的IP代理,但是白嫖来的始终是有缺点的,不然也不会有人专门去卖IP代理了

    白嫖来的IP有稳定性差、速度慢的缺点,所以土豪可以忽视本文...

    展开全文
  • IP代理池检测代理可用性

    万次阅读 2019-05-23 19:01:44
    在《基于Scrapy的IP代理池搭建》一文中,我们将从网页爬取到的免费代理IP按照如下格式保存到了Redis的 proxies:unchecked:list 队列中。 同时,为了避免同一代理IP被重复存储,在将代理保存到 proxies:unch...

    目录

    项目代码 

    utils.py

    settings.py

    proxy_queue.py

     check_proxy.py

     运行方法


    《基于Scrapy的IP代理池搭建》一文中,我们将从网页爬取到的免费代理IP按照如下格式保存到了Redis的 proxies:unchecked:list 队列中。

    同时,为了避免同一代理IP被重复存储,在将代理保存到 proxies:unchecked:list 队列之前,会先将其 URL (例如:https://39.98.254.72:3128)保存到 proxies:unchecked:set 集合中用来进行去重校验。

    众所周知,代理IP都是有时效性的。不可避免地,你会发现爬取到 proxies:unchecked:list 队列中的代理大部分都是不可用的,所以在使用代理IP之前还需要对代理IP的可用性进行验证,验证的方法就是:使用代理IP去请求指定URL,根据返回的响应判断代理IP是否可用。

    废话到此为止,接下来呈上验证代理IP可用性的代码,项目完整目录如下。

    项目代码  

    utils.py

     utils.py 是一个工具类,包含了一些常用操作,比如:剔除字符串的首位空白,获取代理IP的URL,更新代理IP的信息。

    # -*- coding: utf-8 -*-
    import logging
    from settings import PROXY_URL_FORMATTER
    
    # 设置日志的输出样式
    logging.basicConfig(level=logging.INFO,
                        format='[%(asctime)-15s] [%(levelname)8s] [%(name)10s ] - %(message)s (%(filename)s:%(lineno)s)',
                        datefmt='%Y-%m-%d %T'
                        )
    logger = logging.getLogger(__name__)
    
    
    # 剔除字符串的首位空格
    def strip(data):
        if data is not None:
            return data.strip()
        return data
    
    # 获取代理IP的url地址
    def _get_url(proxy):
        return PROXY_URL_FORMATTER % {'schema': proxy['schema'], 'ip': proxy['ip'], 'port': proxy['port']}
    
    # 根据请求结果更新代理IP的字段信息
    def _update(proxy, successed=False):
        proxy['used_total'] = proxy['used_total'] + 1
        if successed:
            proxy['continuous_failed'] = 0
            proxy['success_times'] = proxy['success_times'] + 1
        else:
            proxy['continuous_failed'] = proxy['continuous_failed'] + 1

    settings.py

    settings.py 汇聚了整个项目的配置信息。 

    # 指定Redis的主机名和端口
    REDIS_HOST = '172.16.250.238'
    REDIS_PORT = 6379
    REDIS_PASSWORD = 123456
    
    # 保存已经检验的代理的 Redis key 格式化字符串
    PROXIES_REDIS_FORMATTER = 'proxies::{}'
    
    # 保存已经检验的代理
    PROXIES_REDIS_EXISTED = 'proxies::existed'
    
    # 保存未检验代理的Redis key
    PROXIES_UNCHECKED_LIST = 'proxies:unchecked:list'
    
    # 已经存在的未检验HTTP代理和HTTPS代理集合
    PROXIES_UNCHECKED_SET = 'proxies:unchecked:set'
    
    # 最多连续失败几次
    MAX_FAILURE_TIMES = 2
    
    # 代理地址的格式化字符串
    PROXY_URL_FORMATTER = '%(schema)s://%(ip)s:%(port)s'
    
    BASE_HEADERS = {
        'Connection': 'close',
        'Accept': '*/*',
        'Accept-Encoding': 'gzip, deflate, sdch',
        'Accept-Language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7'
    }
    
    USER_AGENT_LIST = [
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
        "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
        "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
    ]
    
    # 检验代理可用性的请求地址
    PROXY_CHECK_URLS = {'https': ['https://blog.csdn.net/pengjunlee/article/details/81212250',
                                  'https://blog.csdn.net/pengjunlee/article/details/54974260', 'https://icanhazip.com'],
                        'http': ['http://blog.csdn.net/pengjunlee/article/details/80919833',
                                 'http://blog.csdn.net/pengjunlee/article/details/81589972', 'http://icanhazip.com']}
    

    proxy_queue.py

    proxy_queue.py 定义了两个代理存储队列类:刚刚爬取到的尚未检测过可用性的代理IP队列(UncheckQueue)和已经检测过可用性的代理IP队列(CheckQueue,该队列中的代理IP也需要定时反复检测可用性)。

    # -*- coding: utf-8 -*-
    import json
    from utils import _get_url
    from settings import PROXIES_REDIS_EXISTED, PROXIES_REDIS_FORMATTER, PROXIES_UNCHECKED_LIST, PROXIES_UNCHECKED_SET, \
        MAX_FAILURE_TIMES
    
    """
    Proxy Queue Base Class
    """
    class BaseQueue(object):
    
        def __init__(self, server):
            """Initialize the proxy queue instance
    
            Parameters
            ----------
            server : StrictRedis
                Redis client instance
            """
            self.server = server
    
        def _is_existed(self, proxy):
            """判断当前代理是否已经存在"""
            added = self.server.sadd(PROXIES_REDIS_EXISTED, _get_url(proxy))
            return added == 0
    
        def push(self, proxy):
            """根据检验结果,将代理放入相应队列"""
            if not self._is_existed(proxy) and proxy['continuous_failed'] < MAX_FAILURE_TIMES:
                key = PROXIES_REDIS_FORMATTER.format(proxy['schema'])
                self.server.rpush(key, json.dumps(proxy, ensure_ascii=False))
    
        def pop(self, schema, timeout=0):
            """Pop a proxy"""
            raise NotImplementedError
    
        def __len__(self, schema):
            """Return the length of the queue"""
            raise NotImplementedError
    
    
    class CheckedQueue(BaseQueue):
        """待检测的代理队列"""
    
        def __len__(self, schema):
            """Return the length of the queue"""
            return self.server.llen(PROXIES_REDIS_FORMATTER.format(schema))
    
        def pop(self, schema, timeout=0):
            """从未检测列表弹出一个待检测的代理"""
            if timeout > 0:
                p = self.server.blpop(PROXIES_REDIS_FORMATTER.format(schema), timeout)
                if isinstance(p, tuple):
                    p = p[1]
            else:
                p = self.server.lpop(PROXIES_REDIS_FORMATTER.format(schema))
            if p:
                p = eval(p)
                self.server.srem(PROXIES_REDIS_EXISTED, _get_url(p))
                return p
    
    
    class UncheckedQueue(BaseQueue):
        """已检测的代理队列"""
    
        def __len__(self, schema=None):
            """Return the length of the queue"""
            return self.server.llen(PROXIES_UNCHECKED_LIST)
    
        def pop(self, schema=None, timeout=0):
            """从未检测列表弹出一个待检测的代理"""
            if timeout > 0:
                p = self.server.blpop(PROXIES_UNCHECKED_LIST, timeout)
                if isinstance(p, tuple):
                    p = p[1]
            else:
                p = self.server.lpop(PROXIES_UNCHECKED_LIST)
            if p:
                p = eval(p)
                self.server.srem(PROXIES_UNCHECKED_SET, _get_url(p))
                return p

     check_proxy.py

    使用 OptionParser 模块,通过从命令终端传入不同参数来控制检测不同代理队列的可用性。 

    # encoding=utf-8
    import redis
    from optparse import OptionParser
    import random
    import requests
    from utils import logger, _get_url, _update
    from proxy_queue import CheckedQueue, UncheckedQueue
    from settings import USER_AGENT_LIST, BASE_HEADERS, REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, PROXY_CHECK_URLS
    
    USAGE = "usage: python check_proxy.py [ -c -s <schema>] or [-u]"
    
    parser = OptionParser(USAGE)
    parser.add_option("-c", "--checked", action="store_true", dest="checked", help="check the proxies already checked")
    parser.add_option("-u", "--unchecked", action="store_false", dest="checked", help="check the proxies to be checked")
    parser.add_option("-s", "--schema", action="store", dest="schema", type="choice", choices=['http', 'https'],
                      help="the schema of the proxies to be checked")
    options, args = parser.parse_args()
    
    r = redis.StrictRedis(host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD)
    if options.checked:
        schema = options.schema
        if schema is None:
            logger.error("使用 -c 参数时,需要指定 -s 参数!!!")
        proxy_queue = CheckedQueue(r)
    else:
        schema = None
        proxy_queue = UncheckedQueue(r)
    
    # 获取当前待检测队列中代理的数量
    count = proxy_queue.__len__(schema=schema)
    while count > 0:
    
        logger.info("待检测代理数量: " + str(count))
        count = count - 1
    
        # 获取代理
        proxy = proxy_queue.pop(schema=options.schema)
        proxies = {proxy['schema']: _get_url(proxy)}
    
        # 初始化计数字段值
        if "used_total" not in proxy:
            proxy['used_total'] = 0
        if "success_times" not in proxy:
            proxy['success_times'] = 0
        if "continuous_failed" not in proxy:
            proxy['continuous_failed'] = 0
        # 构造请求头
        headers = dict(BASE_HEADERS)
        if 'User-Agent' not in headers.keys():
            headers['User-Agent'] = random.choice(USER_AGENT_LIST)
    
        for url in PROXY_CHECK_URLS[proxy['schema']]:
            try:
                # 使用代理发送请求,获取响应
                response = requests.get(url, headers=headers, proxies=proxies, timeout=5)
            except BaseException:
                logger.info("使用代理< " + _get_url(proxy) + " > 请求 < " + url + " > 结果: 失败 ")
                successed = False
            else:
                if (response.status_code == 200):
                    logger.info("使用代理< " + _get_url(proxy) + " > 请求 < " + url + " > 结果: 成功 ")
                    successed = True
                    break
                else:
                    logger.info("使用代理< " + _get_url(proxy) + " > 请求 < " + url + " > 结果: 失败 ")
                    successed = False
    
        if options.checked:
            # 已检测过的代理,根据检测结果更新代理信息
            _update(proxy, successed=successed)
            # 将代理返还给队列
            proxy_queue.push(proxy)
        elif successed:
            # 首次检测的代理,如果可用直接放入可用队列
            proxy_queue.push(proxy)

     运行方法

     打开命令行终端,执行如下命令开始检测代理IP的可用性:

    python check_proxy.py -u # 检测 proxies:unchecked:list 队列中代理的可用性
    python check_proxy.py -c -s http # 检测 proxies::http 队列中代理的可用性
    python check_proxy.py -c -s https # 检测 proxies::https 队列中代理的可用性

     例如:

    [root@localhost proxy_check]# python3 /usr/local/src/python_projects/proxy_check/check_proxy.py -c -s http
    [2019-05-23 20:15:18] [    INFO] [     utils ] - 待检测代理数量: 437 (check_proxy.py:33)
    [2019-05-23 20:15:23] [    INFO] [     utils ] - 使用代理< http://5.202.192.146:8080 > 请求 < http://blog.csdn.net/pengjunlee/article/details/80919833 > 结果: 失败  (check_proxy.py:58)
    [2019-05-23 20:15:28] [    INFO] [     utils ] - 使用代理< http://5.202.192.146:8080 > 请求 < http://blog.csdn.net/pengjunlee/article/details/81589972 > 结果: 失败  (check_proxy.py:58)
    [2019-05-23 20:15:34] [    INFO] [     utils ] - 使用代理< http://5.202.192.146:8080 > 请求 < http://icanhazip.com > 结果: 失败  (check_proxy.py:58)
    [2019-05-23 20:15:34] [    INFO] [     utils ] - 待检测代理数量: 436 (check_proxy.py:33)
    [2019-05-23 20:15:35] [    INFO] [     utils ] - 使用代理< http://60.217.137.22:8060 > 请求 < http://blog.csdn.net/pengjunlee/article/details/80919833 > 结果: 成功  (check_proxy.py:63)

    Github地址:https://github.com/pengjunlee/proxy_check

    展开全文
  • 基于Scrapy的IP代理池搭建

    万次阅读 2019-05-15 16:27:54
    一、为什么要搭建爬虫代理池 二、搭建思路 三、搭建代理池 items.py kuai_proxy.py middlewares.py pipelines.py settings.py utils.py 一、为什么要搭建爬虫代理池 在众多的网站防爬措施中,有一种是根据...

    目录

    一、为什么要搭建爬虫代理池

    二、搭建思路

    三、搭建代理池

    items.py

    kuai_proxy.py

    middlewares.py

    pipelines.py

    settings.py

    utils.py


    一、为什么要搭建爬虫代理池

    在众多的网站防爬措施中,有一种是根据ip的访问频率进行限制,即在某一时间段内,当某个ip的访问次数达到一定的阀值时,该ip就会被拉黑、在一段时间内禁止访问。

    应对的方法有两种:

    1. 降低爬虫的爬取频率,避免IP被限制访问,缺点显而易见:会大大降低爬取的效率。

    2. 搭建一个IP代理池,使用不同的IP轮流进行爬取。

    二、搭建思路

    1、从代理网站(如:西刺代理、快代理、云代理、无忧代理)爬取代理IP;

    2、验证代理IP的可用性(使用代理IP去请求指定URL,根据响应验证代理IP是否生效);

    3、将可用的代理IP保存到数据库;

    《Python爬虫代理池搭建》一文中我们已经使用Python的 requests 模块简单实现了一个IP代理池搭建,但是爬取速度较慢。由于西刺代理、快代理和云代理等网站需要爬取的IP代理列表页多达上千页,使用此种方法来爬取其实并不适合。

    本文将以快代理网站的IP代理爬取为例,示例如何使用 Scrapy-Redis 来爬取代理IP。

    三、搭建代理池

    scrapy 项目的目录结构如下:

    items.py

    # -*- coding: utf-8 -*-
    import re
    import scrapy
    from proxy_pool.settings import PROXY_URL_FORMATTER
    
    schema_pattern = re.compile(r'http|https$', re.I)
    ip_pattern = re.compile(r'^([0-9]{1,3}.){3}[0-9]{1,3}$', re.I)
    port_pattern = re.compile(r'^[0-9]{2,5}$', re.I)
    
    
    class ProxyPoolItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        '''
            {
                "schema": "http", # 代理的类型
                "ip": "127.0.0.1", # 代理的IP地址
                "port": "8050", # 代理的端口号
                "original":"西刺代理",
                "used_total": 11, # 代理的使用次数
                "success_times": 5, # 代理请求成功的次数
                "continuous_failed": 3, # 使用代理发送请求,连续失败的次数
                "created_time": "2018-05-02" # 代理的爬取时间
            }
        '''
        schema = scrapy.Field()
        ip = scrapy.Field()
        port = scrapy.Field()
        original = scrapy.Field()
        used_total = scrapy.Field()
        success_times = scrapy.Field()
        continuous_failed = scrapy.Field()
        created_time = scrapy.Field()
    
        # 检查IP代理的格式是否正确
        def _check_format(self):
            if self['schema'] is not None and self['ip'] is not None and self['port'] is not None:
                if schema_pattern.match(self['schema']) and ip_pattern.match(self['ip']) and port_pattern.match(
                        self['port']):
                    return True
            return False
    
        # 获取IP代理的url
        def _get_url(self):
            return PROXY_URL_FORMATTER % {'schema': self['schema'], 'ip': self['ip'], 'port': self['port']}

    kuai_proxy.py

    # -*- coding: utf-8 -*-
    import re
    import time
    import scrapy
    from proxy_pool.utils import strip, logger
    from proxy_pool.items import ProxyPoolItem
    
    
    class KuaiProxySpider(scrapy.Spider):
        name = 'kuai_proxy'
        allowed_domains = ['kuaidaili.com']
        start_urls = ['https://www.kuaidaili.com/free/inha/1/', 'https://www.kuaidaili.com/free/intr/1/']
    
        def parse(self, response):
            logger.info('正在爬取:< ' + response.request.url + ' >')
            tr_list = response.css("div#list>table>tbody tr")
            for tr in tr_list:
                ip = tr.css("td[data-title='IP']::text").get()
                port = tr.css("td[data-title='PORT']::text").get()
                schema = tr.css("td[data-title='类型']::text").get()
                if schema.lower() == "http" or schema.lower() == "https":
                    item = ProxyPoolItem()
                    item['schema'] = strip(schema).lower()
                    item['ip'] = strip(ip)
                    item['port'] = strip(port)
                    item['original'] = '快代理'
                    item['created_time'] = time.strftime('%Y-%m-%d', time.localtime(time.time()))
                    if item._check_format():
                        yield item
            next_page = response.xpath("//a[@class='active']/../following-sibling::li/a/@href").get()
            if next_page is not None:
                next_url = 'https://www.kuaidaili.com' + next_page
                yield scrapy.Request(next_url)

    middlewares.py

    # -*- coding: utf-8 -*-
    
    import random
    from proxy_pool.utils import logger
    
    
    # 随机选择 IP 代理下载器中间件
    class RandomProxyMiddleware(object):
    
        # 从 settings 的 PROXIES 列表中随机选择一个作为代理
        def process_request(self, request, spider):
            proxy = random.choice(spider.settings['PROXIES'])
            request.meta['proxy'] = proxy
            return None
    
    
    # 随机选择 User-Agent 的下载器中间件
    class RandomUserAgentMiddleware(object):
        def process_request(self, request, spider):
            # 从 settings 的 USER_AGENTS 列表中随机选择一个作为 User-Agent
            user_agent = random.choice(spider.settings['USER_AGENT_LIST'])
            request.headers['User-Agent'] = user_agent
            return None
    
        def process_response(self, request, response, spider):
            # 验证 User-Agent 设置是否生效
            logger.info("headers ::> User-Agent = " + str(request.headers['User-Agent'], encoding="utf8"))
            return response

    pipelines.py

    # -*- coding: utf-8 -*-
    
    import json
    import redis
    from proxy_pool.settings import REDIS_HOST,REDIS_PORT,REDIS_PARAMS,PROXIES_UNCHECKED_LIST,PROXIES_UNCHECKED_SET
    
    server = redis.StrictRedis(host=REDIS_HOST, port=REDIS_PORT,password=REDIS_PARAMS['password'])
    
    class ProxyPoolPipeline(object):
    
        # 将可用的IP代理添加到代理池队列
        def process_item(self, item, spider):
            if not self._is_existed(item):
                server.rpush(PROXIES_UNCHECKED_LIST, json.dumps(dict(item),ensure_ascii=False))
    
        # 检查IP代理是否已经存在
        def _is_existed(self,item):
            added = server.sadd(PROXIES_UNCHECKED_SET, item._get_url())
            return added == 0

    settings.py

    # -*- coding: utf-8 -*-
    BOT_NAME = 'proxy_pool'
    
    SPIDER_MODULES = ['proxy_pool.spiders']
    NEWSPIDER_MODULE = 'proxy_pool.spiders'
    
    # 保存未检验代理的Redis key
    PROXIES_UNCHECKED_LIST = 'proxies:unchecked:list'
    
    # 已经存在的未检验HTTP代理和HTTPS代理集合
    PROXIES_UNCHECKED_SET = 'proxies:unchecked:set'
    
    # 代理地址的格式化字符串
    PROXY_URL_FORMATTER = '%(schema)s://%(ip)s:%(port)s'
    
    # 通用请求头字段
    DEFAULT_REQUEST_HEADERS = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7',
        'Connection': 'keep-alive'
    }
    
    # 请求太频繁会导致 503 ,在此设置 5 秒请求一次
    DOWNLOAD_DELAY = 5  # 250 ms of delay
    
    USER_AGENT_LIST = [
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
        "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
        "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
    ]
    
    # Obey robots.txt rules
    ROBOTSTXT_OBEY = False
    
    # Enable or disable downloader middlewares
    # See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
    DOWNLOADER_MIDDLEWARES = {
        'proxy_pool.middlewares.RandomUserAgentMiddleware': 543,
        #   'proxy_pool.middlewares.RandomProxyMiddleware': 544,
    }
    
    ITEM_PIPELINES = {
        'proxy_pool.pipelines.ProxyPoolPipeline': 300,
    }
    
    PROXIES = [
        "https://171.13.92.212:9797",
        "https://164.163.234.210:8080",
        "https://143.202.73.219:8080",
        "https://103.75.166.15:8080"
    ]
    
    ######################################################
    ##############下面是Scrapy-Redis相关配置################
    ######################################################
    
    # 指定Redis的主机名和端口
    REDIS_HOST = '172.16.250.238'
    REDIS_PORT = 6379
    REDIS_PARAMS = {'password': '123456'}
    
    # 调度器启用Redis存储Requests队列
    SCHEDULER = "scrapy_redis.scheduler.Scheduler"
    
    # 确保所有的爬虫实例使用Redis进行重复过滤
    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
    
    # 将Requests队列持久化到Redis,可支持暂停或重启爬虫
    SCHEDULER_PERSIST = True
    
    # Requests的调度策略,默认优先级队列
    SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'

    utils.py

    # -*- coding: utf-8 -*-
    import logging
    
    # 设置日志输出格式
    logging.basicConfig(level=logging.INFO,
                        format='[%(asctime)-15s] [%(levelname)8s] [%(name)10s ] - %(message)s (%(filename)s:%(lineno)s)',
                        datefmt='%Y-%m-%d %T'
                        )
    logger = logging.getLogger(__name__)
    
    # Truncate header and tailer blanks
    def strip(data):
        if data is not None:
            return data.strip()
        return data

     

    展开全文
  • 一、手动更新IP池 1.在settings配置文件中新增IP池: IPPOOL=[ {"ipaddr":"61.129.70.131:8080"}, {"ipaddr":"61.152.81.193:9100"}, {"ipaddr":"120....
  • IP代理池

    万次阅读 2018-08-02 12:08:46
    该项目旨在提供批量免费的代理IP地址,思路参考自作者崔庆才的书籍《Python3 网络爬虫开发实战》第九章–代理的使用–代理池的维护,在此感谢作者的无私贡献!项目的分模块思想借鉴了作者的思路,但代码实现不同。 ...
  • 声明 因为最近搞一些网站总是会遇到 IP 被封了,很难受呀…财大气粗去买?...今天分享一下一个很好的GitHub项目,项目地址:https://github.com/Python3WebSpider/ProxyPool.git 很好的一个开源代理 IP池,...
  • 代理池就是用于应付网站的反爬虫的备用代理ip集合。 做过爬虫都知道,在抓取某些网站的时候,如果你抓取的频率太高了,你的ip就会被该网站封掉或者说屏蔽掉,接下来你就会爬取失败,所以此时你就需要使用代理来解决...
  • 搭建IP代理池伪装IP地址

    千次阅读 2019-03-23 21:21:08
    1、下载开源IP代理池源代码 https://github.com/Python3WebSpider/ProxyPool 2、安装Redis https://github.com/MicrosoftArchive/redis/releases 3、安装相关所需的 python 模块 Windows PowerShell 版权...
  • IP代理池的Python实现

    千次阅读 2015-11-19 09:19:51
    爬虫采集数据时,如果频繁的访问某个网站,会被封IP,有些是禁止访问3小时,有些是直接拉黑名单。为了避免被禁,一般采取的措施有三种: ...国内提供IP代理的网站有很多,我们以其中的一个为例:h
  • selenium 和 IP代理池

    千次阅读 2019-05-15 21:55:00
    3.1 selenium selenium: Selenium 是一个自动化测试工具,利用它可以 驱动浏览器 执行特定的动作,如点击、下拉等操作(模拟浏览器操作) 同时还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬 ...
  • Java实现Ip代理池

    千次阅读 2019-01-19 14:49:20
    设置Ip代理很多时候都会有用到,尤其是在写爬虫相关项目的时候。虽然自己目前没有接触这种需求,但由于最近比较闲,就写着当作练习吧 爬取代理IP 爬取 关于爬取代理IP,国内首先想到的网站当然是 西刺代理 。首先写...
  • python的ip代理池

    2019-12-02 11:14:15
    爬取代理然后验证代理,将可用代理放入txt文件。 辣鸡编码,大佬们轻喷,有问题留言。。。。。。。谢谢。 结果如图 import requests from scrapy import Selector start_url = 'http://www.89ip.cn/index_1.html' ...
  • go语言IP代理池

    2019-09-26 17:47:35
    https://github.com/henson/ProxyPool 其中pkg/models/models.go 191行报错了 pkg/models/models.go:191:36: cannot use "github.com/go-xorm/core".LOG_WARNING (type "github.com/go-xorm/core".LogLevel) as ...
  • python建立IP代理池

    千次阅读 2018-08-27 15:54:23
    #!coding=utf-8 import requests import re import pandas as pd def get_proxy(): ""... 获取代理 ... # 获取xicidaili的高匿代理 ##proxy_info_list = [] # 抓取到的ip列表 ip_list=[] dk_list=[] ...
  • 免费的ip代理池

    2020-02-21 15:58:03
    python写的一个ip池服务器 原地址 github:https://github.com/jhao104/proxy_pool 外国的网站太慢,我拉到gitee了: https://gitee.com/panlufei/proxy_pool 我自己的服务器: 47.104.17.47:5010 (可以当测试使用, 不要...
  • python制作ip代理池

    千次阅读 2018-10-23 17:39:59
    # !/usr/bin/env python # -*- coding: utf-8 -*- # @Version : 1.0 # @Time : 2018/10/23 上午10:40 # @Author : Yeoman # @Description : import urllib.request import lxml.etree import ...

空空如也

1 2 3 4 5 ... 20
收藏数 24,740
精华内容 9,896
关键字:

ip代理池