爬蟲技術 - 代理

使用爬蟲的時候肯定會有頻繁訪問某一網站的情況,這個時候有些服務器會識別到這是非正常訪問,就會把請求的IP禁掉,這個時候就需要用代理了。就好比現實生活中,我需要向A借一件東西,但是我跟A是仇人,直接向他借的話他不會借給我,這個時候我就讓B幫我向A借,就說他要用,然後B借到東西之後再把東西給我用,這時,B就是我的代理了。


代理選擇

針對不需要用戶登錄,cookie驗證的網站,一般選擇動態高匿代理。
對於需要用戶登錄,身份認證的。一般選擇靜態IP。

代理獲取

使用代理時一般需要建一個代理池,從代理池中獲取有效代理,然後通過代理去訪問內容網站。
本節將結合代碼介紹代理池的使用。

爲了使用方便,web框架簡單使用flask。api接口類如下:

from flask import Flask, jsonify
from proxy.ProxyManager import ProxyManager

app = Flask('ProxyPool')


@app.route("/")
def hello():
    return "Hello coder"

# 隨機返回一個代理
@app.route("/get")
def get():
    return jsonify(ProxyManager().get())

# 返回所有有效代理
@app.route("/get_all")
def get_all():
    return jsonify(ProxyManager().get_all())

# 返回代理數據庫代理數量
@app.route("/get_status")
def get_status():
    return jsonify(ProxyManager().get_status())


if __name__ == '__main__':
    app.run()

代理管理類ProxyManager如下:

# coding=utf-8
from ProxyGetter import ProxyGetter
from dao.RedisClient import RedisClient


class ProxyManager(object):
    """
    代理管理類
    """
    def __init__(self):
        self.db_client = RedisClient()

    def refresh(self):
        for proxy in ProxyGetter.get_proxy_one():
            self.db_client.put(proxy, 'raw')

    def get(self):
        return self.db_client.get()

    def get_all(self):
        return self.db_client.get_all()

    def get_status(self):
        return self.db_client.get_status()


if __name__ == '__main__':
    m = ProxyManager()
    m.refresh()
    print(m.get_all())
    print(m.get_status())

db使用redis做數據庫:

# coding: utf-8
from base.base_redis import redis_client


class RedisClient(object):

    def __init__(self):
        self.redis_client = redis_client

    def get(self):
        # 隨機返回集合成員
        proxy = self.redis_client.srandmember('useful')
        if proxy:
            return proxy.decode('ascii')
        return None

    def put(self, proxy, sname='useful'):
        return self.redis_client.sadd(sname, proxy)

    def get_all(self):
        # 返回全部集合成員
        proxies = self.redis_client.smembers('useful')
        if proxies:
            proxy_list = []
            for i in proxies:
                proxy_list.append(i.decode('ascii'))
            return proxy_list
        return None

    def get_status(self):
        status = dict()
        # 獲取集合的成員數
        status['useful'] = self.redis_client.scard('useful')
        status['raw'] = self.redis_client.scard('raw')
        return status


if __name__ == '__main__':
    r = RedisClient()
    print r.get()

redis_client如下:

import redis
import settings

redis_host = settings.get('redis', 'host')
redis_port = settings.get('redis', 'port')

redis_client = redis.Redis(redis_host, redis_port)

其中settings爲配置解析文件,在config配置文件中配置參數,通過settings進行解析。settings文件在博主之前的ORM框架之Sqlalchemy一文中介紹過。

代理獲取類如下:

import logging
from util.UtilFunction import get_html_tree


class ProxyGetter(object):

    def __init__(self):
        pass

    @classmethod
    def get_proxy_one(cls):
        url = "http://www.xicidaili.com/nn/"
        html_tree = get_html_tree(url)
        proxies = html_tree.xpath('//table[@id="ip_list"]//tr')[1::]
        for p in proxies:
            try:
                ip = p.xpath('.//td[2]/text()')[0]
                port = p.xpath('.//td[3]/text()')[0]
                yield ip + ":" + port
            except Exception, e:
                logging.exception(e)


if __name__ == '__main__':
    for i in ProxyGetter.get_proxy_one():
        print i

這裏以西刺爲例,獲取其提供的高匿代理。當然,實際上免費代理很多都是無效的,無法使用的,因此在使用之前需要進行驗證代理有效性。

代理解析工具類UtilFunction.py如下:

from WebRequest import WebRequest
from lxml import etree


def get_html_tree(url):
    wr = WebRequest()
    html = wr.get(url).content
    return etree.HTML(html)

WebRquest類如下:

# coding:utf-8
import requests


class WebRequest(object):
    def __init__(self):
        pass

    @property
    def header(self):
        headers = {
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'Connection': 'keep-alive',
            'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) ' \
                          'Chrome/62.0.3202.94 Safari/537.36'
        }
        return headers

    def get(self, url, header=None):
        headers = self.header  # 公共header
        if header and isinstance(header, dict):
            headers.update(header)
        html = requests.get(url, headers=headers)
        return html

至此一個簡單的原始代理收集模塊已經完成,執行ProxyManager主函數之後,就從代理網站獲取到原始代理,並存儲到redis數據庫中了。查詢redis中數據:
在這裏插入圖片描述
運行程序後通過api接口返回get_status,結果如下:

{"raw":100,"useful":0}

原始代理庫中有100條代理記錄,有效代理庫中無代理記錄。

接下來就需要進一步對原始代理進行驗證,移除掉無效代理,將有效代理保存到useful表中。

參考資料

[1]https://blog.csdn.net/sinat_34200786/article/details/79451499

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章