想要在Scrapy领域无限制畅游,做好伪装是第一步,于是乎,抓取代理IP成了很多教程的开始部分。
我十分同意这个观点,既有实际用处,又能作为一个教学,当然,对于初次使用scrapy的我,很多东西也只是在摸索阶段,所以以下内容算不上教学,只能说是练手。
完成代理IP抓取,总共分三个步骤:
这里需要用到的解决方案是:scrapy+mongo+supervisor,scrapy负责抓取,mongo是数据存储的解决方案,supervisor负责监控一个daemon,重复验证已经获得的代理IP。
scrapy教程推荐看官方的版本:scrapy官方文档,即使是翻译过的也可以,要掌握看文档的技能。
scrapy的具体使用这里不一步一步说明了,列出几个我认为叫重要的点:
scrapy startproject GoProxy
scrapy crawl Proxy
关于抓取规则,这是抓取类算法的核心,足够研究很久,在这里,够用足以。
代理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
# -*- 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搞定,纯属喜好问题:)