Python-Scrapy 个人兴趣教程(二):没错,从代理IP开始

想要在Scrapy领域无限制畅游,做好伪装是第一步,于是乎,抓取代理IP成了很多教程的开始部分。

我十分同意这个观点,既有实际用处,又能作为一个教学,当然,对于初次使用scrapy的我,很多东西也只是在摸索阶段,所以以下内容算不上教学,只能说是练手。


完成代理IP抓取,总共分三个步骤:

  • 抓取网络上的代理IP和端口
  • 验证已经抓取的内容
  • 网络上的免费代理IP基本都有时效性,所以需要重复抓取和重复验证

这里需要用到的解决方案是:scrapy+mongo+supervisor,scrapy负责抓取,mongo是数据存储的解决方案,supervisor负责监控一个daemon,重复验证已经获得的代理IP。


scrapy教程推荐看官方的版本:scrapy官方文档,即使是翻译过的也可以,要掌握看文档的技能。

scrapy的具体使用这里不一步一步说明了,列出几个我认为叫重要的点:

  • 生成一个新的scrapy项目:
    scrapy startproject GoProxy

  • scrapy.cfg是一个ini格式的配置文件,配置相关的参数可以都放在这里。
  • spiders目录下放spider的代码,执行抓取的命令跟spider类名有关。例如,我的spider叫 class ProxySpider(CrawlSpider),那么我的执行命令为:
    scrapy crawl Proxy
  • items是一个收集抓取内容的容器,没有研究深入,在这个例子里作为传递给mongodb的过程变量使用。
  • pipelines是跟外部数据接口的部分,抓取的IP内容装入items后再pipelines被存入mongodb。

关于抓取规则,这是抓取类算法的核心,足够研究很久,在这里,够用足以。

代理IP抓取没有精确性的要求,10个数据漏掉5个都没关系,所以我这里使用了宽泛的正则表达式直接过滤出IP+PORT的字符串内容。代理IP网站来源于baidu和google搜索的前6页。

这种方法个人学习够用了,要想用在其他方面,这种算法抓取到的IP数量级远远不够...0 0...(一次抓取只能过滤出2000多个IP,验证后只有大概400个有效IP)


这里贴上scapy的部分源码:proxy_spider.c

# Spider for http proxy
# -*- coding: utf-8 -*-

import scrapy
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors import LinkExtractor
from bs4 import BeautifulSoup
from GoProxy.items import GoproxyItem

import re

REG_IP = re.compile(r'((?:(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d))))[^\d]*((\d){1,5})', re.M)

class ProxySpider(CrawlSpider):
    name = "Proxy"
    #allowed_domains = ['xici.net.co', 'youdaili.net']
    start_urls = [
            r"http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=ip%20proxy",
            r"http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=ip%20proxy&pn=10",
            r"http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=ip%20proxy&pn=20",
            r"http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=ip%20proxy&pn=30",
            r"http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=ip%20proxy&pn=40",
            r"http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=ip%20proxy&pn=50",
            r"http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=ip%20proxy&pn=60",
            r"http://www.gfsoso.net/?q=ip+proxy&t=1",
            r"http://www.gfsoso.net/?q=ip+proxy&pn=10",
            r"http://www.gfsoso.net/?q=ip+proxy&pn=20",
            r"http://www.gfsoso.net/?q=ip+proxy&pn=30",
            r"http://www.gfsoso.net/?q=ip+proxy&pn=40",
            r"http://www.gfsoso.net/?q=ip+proxy&pn=50",
            r"http://www.gfsoso.net/?q=ip+proxy&pn=60",
    ]

    rules = (
            Rule(LinkExtractor(allow=(r'',)), callback='parse_item'),
    )

    def parse_item(self, response):
        soup = BeautifulSoup(response.body)
        str_list = [ tag.string or '' for tag in soup.find_all(True) ]
        body_str = ' '.join(str_list)
        items = [ GoproxyItem(ip=group[0], port=group[7], protocol='HTTP') for group in re.findall(REG_IP, body_str) ]
        return items

pipelines.c:

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html

import pymongo
import time
from scrapy.conf import settings

class GoproxyPipeline(object):
    def __init__(self):
        connection = pymongo.MongoClient(settings['MONGODB_SERVER'], settings['MONGODB_PORT'])
        db = connection[settings['MONGODB_DB']]
        self.collection = db[settings['MONGODB_COLLECTION']]

    def process_item(self, item, spider):
        new_proxy = {
            "ip":item['ip'],
            "port":item['port'],
            "protocol":item['protocol'],
        }
        if self.collection.find_one(new_proxy) is None:
            self.collection.insert(new_proxy)

        return item


在调试完成后,用crontab把这个抓取定制为每半小时执行一次,= =保证数据库里的都是新鲜的IP~~~~。

0,30 * * * *  cd /root/work/repos/GoProxy/&&/usr/local/bin/scrapy crawl Proxy


这样,抓取代理IP的初步工作就完成了,下一篇会简单介绍一下代理IP的验证,我使用的是daemon的形式,只要mongodb的对应collection里面有数据,就将数据去除验证,如果验证成功,则放入另一个collection,对于这个存放有效数据的collection也同样有:取出->验证->放回,的过程。至于为什么不用一个collection搞定,纯属喜好问题:)



你可能感兴趣的:(网络,python,server)