九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
小白學(xué) Python 爬蟲(31):自己構(gòu)建一個(gè)簡單的代理池

人生苦短,我用 Python

前文傳送門:

小白學(xué) Python 爬蟲(1):開篇

小白學(xué) Python 爬蟲(2):前置準(zhǔn)備(一)基本類庫的安裝

小白學(xué) Python 爬蟲(3):前置準(zhǔn)備(二)Linux基礎(chǔ)入門

小白學(xué) Python 爬蟲(4):前置準(zhǔn)備(三)Docker基礎(chǔ)入門

小白學(xué) Python 爬蟲(5):前置準(zhǔn)備(四)數(shù)據(jù)庫基礎(chǔ)

小白學(xué) Python 爬蟲(6):前置準(zhǔn)備(五)爬蟲框架的安裝

小白學(xué) Python 爬蟲(7):HTTP 基礎(chǔ)

小白學(xué) Python 爬蟲(8):網(wǎng)頁基礎(chǔ)

小白學(xué) Python 爬蟲(9):爬蟲基礎(chǔ)

小白學(xué) Python 爬蟲(10):Session 和 Cookies

小白學(xué) Python 爬蟲(11):urllib 基礎(chǔ)使用(一)

小白學(xué) Python 爬蟲(12):urllib 基礎(chǔ)使用(二)

小白學(xué) Python 爬蟲(13):urllib 基礎(chǔ)使用(三)

小白學(xué) Python 爬蟲(14):urllib 基礎(chǔ)使用(四)

小白學(xué) Python 爬蟲(15):urllib 基礎(chǔ)使用(五)

小白學(xué) Python 爬蟲(16):urllib 實(shí)戰(zhàn)之爬取妹子圖

小白學(xué) Python 爬蟲(17):Requests 基礎(chǔ)使用

小白學(xué) Python 爬蟲(18):Requests 進(jìn)階操作

小白學(xué) Python 爬蟲(19):Xpath 基操

小白學(xué) Python 爬蟲(20):Xpath 進(jìn)階

小白學(xué) Python 爬蟲(21):解析庫 Beautiful Soup(上)

小白學(xué) Python 爬蟲(22):解析庫 Beautiful Soup(下)

小白學(xué) Python 爬蟲(23):解析庫 pyquery 入門

小白學(xué) Python 爬蟲(24):2019 豆瓣電影排行

小白學(xué) Python 爬蟲(25):爬取股票信息

小白學(xué) Python 爬蟲(26):為啥買不起上海二手房你都買不起

小白學(xué) Python 爬蟲(27):自動化測試框架 Selenium 從入門到放棄(上)

小白學(xué) Python 爬蟲(28):自動化測試框架 Selenium 從入門到放棄(下)

小白學(xué) Python 爬蟲(29):Selenium 獲取某大型電商網(wǎng)站商品信息

小白學(xué) Python 爬蟲(30):代理基礎(chǔ)

引言

前面的代理如果有同學(xué)動手實(shí)踐過,就會發(fā)現(xiàn)一個(gè)問題,現(xiàn)在網(wǎng)上的免費(fèi)代理簡直太坑啦?。。?/p>

經(jīng)常一屏幕好多的代理試下來,沒有幾個(gè)能用的。

當(dāng)然,免費(fèi)的代理嘛,連通率低、延遲高是正常的,人家畢竟是免費(fèi)的。

但是這件事兒有沒有解決方案呢?

這么天資聰穎的小編肯定是想到了辦法了呀。

先來屢屢這件事兒,其實(shí)我們要的不是連通率高,而是我們在使用的時(shí)候,能每次都用到能用的代理。

這件事兒要么我們每次在用的時(shí)候自己手動去試,要么~~~

我們可以寫程序讓程序自己去尋找合適的代理嘛~~~

其實(shí)這一步就是把需要我們手動做的事情變成了程序自動去完成。

代理池

先想一下這個(gè)代理池最少需要有哪些功能:

  • 自動獲取代理

  • 定時(shí)清除不能用的代理

這兩個(gè)是我們的核心訴求,最少要有這兩個(gè)功能,不然這個(gè)代理池也沒有存在的價(jià)值了。

根據(jù)上面兩個(gè)功能,我們來拆解程序的模塊,小編這里定義了三個(gè)模塊,獲取模塊(獲取代理)、存儲模塊(數(shù)據(jù)庫存儲代理)、檢測模塊(定時(shí)檢查代理的可用性)。

那么它們?nèi)叩年P(guān)系就是這樣的:

這里的存儲模塊我們使用 Mysql ,這與存儲模塊為什么選 Mysql ,因?yàn)?Mysql 有表結(jié)構(gòu),給各位同學(xué)展示起來比較清晰,如果需要用于生產(chǎn)環(huán)境的話,建議是用 Redis ,提高效率。

數(shù)據(jù)庫

首先還是貼一下數(shù)據(jù)庫的表結(jié)構(gòu),之前有同學(xué)留言問過小編表結(jié)構(gòu)的事情,是小編偷懶沒有貼。

本次設(shè)計(jì)使用的還是單表模式,一張表走天下就是小編本人了。

至于字段的含義小編就不介紹了,后面的注釋已經(jīng)寫得比較清楚了。

存儲模塊

對于存儲模塊來講,主要的功能是要將我們獲取到的代理保存起來,上面的 Mysql 數(shù)據(jù)庫是存儲模塊的一部分。

基于 OOP 的思想,我們本次寫一個(gè)類 MysqlClient 將所有對于 Mysql 的操作封裝起來,其他模塊需要和數(shù)據(jù)庫產(chǎn)生交互的時(shí)候只需要調(diào)用我們在 MysqlClient 中封裝好的方法即可。

示例代碼如下:

MYSQL_HOST = 'localhost'
MYSQL_PORT = 3306
MYSQL_USER = 'root'
MYSQL_PASSWORD = 'password'
MYSQL_DB ='test'
MYSQL_CHARSET = 'utf8mb4'

import pymysql
import uuid

class MysqlClient(object):
    def __init__(self, host=MYSQL_HOST, port=MYSQL_PORT, user=MYSQL_USER, password=MYSQL_PASSWORD, database=MYSQL_DB, charset=MYSQL_CHARSET):
        """
        初始化 mysql 連接
        :param host: mysql 地址
        :param port: mysql 端口
        :param user: mysql 用戶
        :param password: mysql 密碼
        :param database: mysql scheme
        :param charset: 使用的字符集
        """
        self.conn = pymysql.connect(
            host = host,
            port = port,
            user = user,
            password = password,
            database = database,
            charset = charset
        )

    def add_proxy(self, proxy):
        """
        新增代理
        :param proxy: 代理字典
        :return:
        """
        sql = 'INSERT INTO `proxy_pool` VALUES (%(id)s, %(scheme)s, %(ip)s, %(port)s, %(status)s, %(response_time)s, now(), null )'
        data = {
            "id": str(uuid.uuid1()),
            "scheme": proxy['scheme'],
            "ip": proxy['ip'],
            "port": proxy['port'],
            "status": proxy['status'],
            "response_time": proxy['response_time'],
        }
        self.conn.cursor().execute(sql, data)
        self.conn.commit()

    def find_all(self):
        """
        獲取所有可用代理
        :return:
        """
        sql = 'SELECT * FROM proxy_pool WHERE status = "1" ORDER BY update_date ASC '
        cursor = self.conn.cursor()
        cursor.execute(sql)
        res = cursor.fetchall()
        cursor.close()
        self.conn.commit()
        return res

    def update_proxy(self, proxy):
        """
        更新代理信息
        :param proxy: 需要更新的代理
        :return:
        """
        sql = 'UPDATE proxy_pool SET scheme = %(scheme)s, ip = %(ip)s, port = %(port)s, status = %(status)s, response_time = %(response_time)s, update_date = now()  WHERE id = %(id)s '
        data = {
            "id": proxy['id'],
            "scheme": proxy['scheme'],
            "ip": proxy['ip'],
            "port": proxy['port'],
            "status": proxy['status'],
            "response_time": proxy['response_time'],
        }
        self.conn.cursor().execute(sql, data)
        self.conn.commit()

在這個(gè)類中,我們首先定義了一些常量,都是和數(shù)據(jù)庫連接有關(guān)的常量,如 MYSQL_HOST 數(shù)據(jù)庫地址、 MYSQL_PORT 數(shù)據(jù)庫端口、 MYSQL_USER 數(shù)據(jù)庫用戶名、 MYSQL_PASSWORD 數(shù)據(jù)庫密碼、 MYSQL_DB 數(shù)據(jù)庫的 scheme 、 MYSQL_CHARSET 字符集。

接下來定義了一個(gè) MysqlClient 類,定義了一些方法用以執(zhí)行數(shù)據(jù)庫的相關(guān)操作。

  • init(): 初始化方法,在初始化 MysqlClient 這個(gè)類時(shí),同時(shí)初始化了 Mysql 數(shù)據(jù)庫的鏈接信息,獲得了數(shù)據(jù)庫連接 connection 。

  • add_proxy():向數(shù)據(jù)庫中添加代理,并添加相關(guān)信息,包括代理響應(yīng)延時(shí)和健康狀況。

  • find_all():獲取所有數(shù)據(jù)庫可用代理,并根據(jù)更新時(shí)間正序排布,主要用于后續(xù)代理檢查。

  • update_proxy():更新代理信息,主要用戶檢查模塊檢查完代理后更新代理信息,根據(jù)取出當(dāng)前代理的主鍵 id 進(jìn)行更新。

獲取模塊

獲取模塊相對比較簡單,主要功能就是從各個(gè)免費(fèi)代理網(wǎng)站上將我們所需要的代理信息抓取下來。示例如下:

import requests
from pyquery import PyQuery
from MysqlClient import MysqlClient
from VerifyProxy import VerifyProxy

class CrawlProxy(object):

    def __init__(self):
        self.mysql = MysqlClient()
        self.verify = VerifyProxy()

    def get_page(self, url, charset):
        response = requests.get(url)
        response.encoding = charset
        return response.text

    def crawl_ip3366(self, page_num = 3):
        """
        獲取代理 ip3366
        :param page_num:
        :return:
        """
        start_url = 'http://www.ip3366.net/?stype=1&page={}'
        urls = [start_url.format(page) for page in range(1, page_num + 1)]
        for url in urls:
            print('crawl:', url)
            html = self.get_page(url, 'gb2312')
            if html:
                d = PyQuery(html)
                trs = d('.table-bordered tbody tr').items()
                for tr in trs:
                    scheme = tr.find('td:nth-child(4)').text().lower()
                    ip = tr.find('td:nth-child(1)').text()
                    port = tr.find('td:nth-child(2)').text()
                    verify_result = self.verify.verify_proxy(scheme, ip, port)

                    if verify_result["status"] == '1':
                        proxy = {
                            "scheme": scheme,
                            "ip": ip,
                            "port": port,
                            "status": verify_result["status"],
                            "response_time": verify_result["response_time"],
                        }
                        # 存入數(shù)據(jù)庫
                        self.mysql.add_proxy(proxy)
                        print('代理', ip, '連通測試已通過,已保存 Mysql')
                    else:
                        print('代理', ip, '連通測試未通過')

if __name__ == '__main__':
    CrawlProxy().crawl_ip3366()

小編這里出于示例只演示了從 ip3366 上抓取免費(fèi)代理,并且在抓取到代理后,調(diào)用檢查模塊的檢查方法對當(dāng)前的代理進(jìn)行連通性檢查,如果連通性測試未通過則不會寫入數(shù)據(jù)庫中。

檢查模塊

檢查模塊相對也會簡單一些,功能是從數(shù)據(jù)庫中取出所有可以用的代理,進(jìn)行輪詢檢查,看看是不是有代理是連不通的,如果連不通則修改連通性標(biāo)記位,將此代理標(biāo)記為不可用。示例代碼如下:

import requests
from MysqlClient import MysqlClient

class VerifyProxy(object):
    def __init__(self):
        self.mysql = MysqlClient()

    def verify_proxy(self, scheme, ip, port):
        """
        使用百度測試代理的連通性,并返回響應(yīng)時(shí)長(單位:ms)
        :param scheme:
        :param ip:
        :param port:
        :return:
        """
        proxies = {
            scheme: scheme + '://' + ip + ':' + port + '/'
        }
        response_time = 0
        status = '0'
        try:
            response = requests.get(scheme + '://www.baidu.com/get', proxies=proxies)
            if response.ok:
                response_time = round(response.elapsed.total_seconds() * 1000)
                status = '1'
            else:
                response_time = 0
                status = '0'
        except:
            pass
        return {"response_time" : response_time, "status" : status}

    def verify_all(self):
        """
        驗(yàn)證住方法,從數(shù)據(jù)庫中獲取所有代理進(jìn)行驗(yàn)證
        :return:
        """
        results = self.mysql.find_all()
        for result in results:
            res = self.verify_proxy(result[1], result[2], result[3])
            proxy = {
                "id": result[0],
                "scheme": result[1],
                "ip": result[2],
                "port": result[3],
                "status": res["status"],
                "response_time": res["response_time"],
            }
            self.mysql.update_proxy(proxy)
            print('代理驗(yàn)證成功')

if __name__ == '__main__':
    VerifyProxy().verify_all()

小編這里使用的是度娘進(jìn)行連通性測試,如果各位同學(xué)有特殊的需要,可以使用特定的網(wǎng)站進(jìn)行連通性測試。

小結(jié)

本篇的內(nèi)容到這里就結(jié)束了,不過有一點(diǎn)要說明,本篇的示例內(nèi)容只能作為 DEMO 來進(jìn)行測試使用,對于一個(gè)連接池來講,還有很多不完善的地方。

例如檢測模塊應(yīng)該是定時(shí)啟動,自行檢測,現(xiàn)在是靠人手動啟動,不過這個(gè)可以使用各種系統(tǒng)上的定時(shí)任務(wù)來解決。

還有,現(xiàn)在要獲取連接信息只能自己打開數(shù)據(jù)庫從中 Copy ,這里其實(shí)還可以加一個(gè) API 模塊,寫成一個(gè)接口,供其他有需要使用代理的系統(tǒng)進(jìn)行調(diào)用。

獲取模塊現(xiàn)在小編也只是簡單的有一個(gè)網(wǎng)站寫一個(gè)方法,其實(shí)可以使用 Python 高級用法,獲取到類中所有的方法名,然后調(diào)用所需要的方法。

總之,這個(gè) DEMO 非常不完善,等小編下次有空的時(shí)候完善下,到時(shí)候還可以再來一個(gè)推送。

示例代碼

本系列的所有代碼小編都會放在代碼管理倉庫 Github 和 Gitee 上,方便大家取用。

示例代碼-Github

示例代碼-Gitee

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
如何在Python中操作MySQL?
刨根問底,完美解決Django2版本連接MySQL報(bào)錯(cuò)的問題
C#連接MySQL,并完成對數(shù)據(jù)庫的增刪查改
數(shù)據(jù)庫的備份和還原
Python連接MySQL數(shù)據(jù)庫方法介紹(超詳細(xì)!手把手項(xiàng)目案例操作)
Python連接MySQL數(shù)據(jù)庫之pymysql模塊使用
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服