【scrapy】使用方法概要(三)(转)
请初学者作为参考,不建议高手看这个浪费时间】
前两篇大概讲述了scrapy的安装及工作流程。这篇文章主要以一个实例来介绍scrapy的开发流程,本想以教程自带的dirbot作为例子,但感觉大家应该最先都尝试过这个示例,应该都很熟悉,这里不赘述,所以,将用笔者自己第一个较为完整的抓取程序作为示例作为讲解。
首先,要大规模抓取一个网站的内容,必要的资源便是代理ip这一资源,如果不使用代理ip,又追求抓取的速度,很可能会被被抓网站发现行踪并封掉抓取机,所以抓取大量可用的代理ip便是我们第一个任务。
大概这个爬虫要实现以下三个功能:
1. 抓取代理ip,端口信息
2. 验证代理ip,判断其透明性
3. 将可用的代理ip持久化到文件中以供后续抓取程序使用
http://www.cnproxy.com/ 代理服务器网便是一个很好的代理ip的来源,简单看一下,共有12个页面,页面格式相同:
http://www.cnproxy.com/proxy1.html
…
http://www.cnproxy.com/proxy10.html
http://www.cnproxy.com/proxyedu1.html
http://www.cnproxy.com/proxyedu2.html
准备就绪,下面正式开始:
1. 定义item,根据需求,抓取的item最后应该包含如下信息才好用:
#前4个数据为页面可以直接获取的
ip地址
端口
协议类型
地理位置
#后三个数据为pipeline中后期得到的数据,很有用
代理类型
延迟
时间戳
所以定义代码如下:

1 # Define here the models for your scraped items
2 #
3 # See documentation in:
4 # http://doc.scrapy.org/topics/items.html
5
6 from scrapy.item import Item, Field
7
8 class ProxyItem(Item):
9 address = Field()
10 port = Field()
11 protocol = Field()
12 location = Field()
13
14 type = Field() # 0: anonymity #1 nonanonymity
15 delay = Field() # in second
16 timestamp = Field()

2. 定义爬虫
爬虫中做的主要工作就是设置初始化urls,即【种子】,【可不是那种种子~是这种种子~】
然后在默认的parse函数中使用xpath可以轻松的获得所需要的字段,比如
addresses = hxs.select('//tr[position()>1]/td[position()=1]').re('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')
可以获得ip信息的数组
locations = hxs.select('//tr[position()>1]/td[position()=4]').re('<td>(.*)<\/td>')
可以获得地理位置信息的数组
唯一有点麻烦的就是端口信息,网站站长可能想到数据会被抓取的可能,所以端口的输出使用了js输出,这确实增加了抓取的难度,scrapy和一般的爬虫是不具备浏览器的javascript解释器的,也不会执行这些js代码,所以,爬虫拿到的html代码中的端口号好没有被输出出来~
源码是这个样子
所以,一定在html的上部,会有这些‘r’的定义,不难发现
经过几次刷新,发现这些定义并不是动态的,所以就简单些,直接拿到代码中的+r+d+r+d信息,将+号替换为空,将r替换成8,d替换成0即可,所以可以声明下边这样的一个map
port_map = {'z':'3','m':'4','k':'2','l':'9','d':'0','b':'5','i':'7','w':'6','r':'8','c':'1','+':''}
具体的爬虫代码如下

1 from scrapy.contrib.spiders import CrawlSpider, Rule
2 from scrapy.selector import HtmlXPathSelector
3 from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
4 from proxy.items import ProxyItem
5 import re
6
7 class ProxycrawlerSpider(CrawlSpider):
8 name = 'cnproxy'
9 allowed_domains = ['www.cnproxy.com']
10 indexes = [1,2,3,4,5,6,7,8,9,10]
11 start_urls = []
12 for i in indexes:
13 url = 'http://www.cnproxy.com/proxy%s.html' % i
14 start_urls.append(url)
15 start_urls.append('http://www.cnproxy.com/proxyedu1.html')
16 start_urls.append('http://www.cnproxy.com/proxyedu2.html')
17
18 def parse(self, response):
19 hxs = HtmlXPathSelector(response)
20 addresses = hxs.select('//tr[position()>1]/td[position()=1]').re('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')
21 protocols = hxs.select('//tr[position()>1]/td[position()=2]').re('<td>(.*)<\/td>')
22 locations = hxs.select('//tr[position()>1]/td[position()=4]').re('<td>(.*)<\/td>')
23 ports_re = re.compile('write\(":"(.*)\)')
24 raw_ports = ports_re.findall(response.body);
25 port_map = {'z':'3','m':'4','k':'2','l':'9','d':'0','b':'5','i':'7','w':'6','r':'8','c':'1','+':''}
26 ports = []
27 for port in raw_ports:
28 tmp = port
29 for key in port_map:
30 tmp = tmp.replace(key, port_map[key]);
31 ports.append(tmp)
32 items = []
33 for i in range(len(addresses)):
34 item = ProxyItem()
35 item['address'] = addresses[i]
36 item['protocol'] = protocols[i]
37 item['location'] = locations[i]
38 item['port'] = ports[i]
39 items.append(item)
40 return items
41 ~

3. 执行pipeline,过滤并检查抓取到的代理ip,并将其持久化到文件中
一般性的校验过程我就不赘述了,直接介绍如果验证代理可用性及透明性的方法。
这需要另一个cgi程序的帮助。简单来说一个代理是否透明,就是在做中转的时候是否会将源ip放到请求包中并能够被被抓取方获取,如果能,就说明这个代理不是透明的,使用的时候就要多留意。
一般非透明代理ip会将源ip放到HTTP_X_FORWARDED_FOR字段中,为了更严谨些,另一个cgi脚本将服务器能获取到的所有跟ip有关的数据echo出来,php代码如下:

1 <?php
2
3 echo "PROXYDETECTATION</br>";
4 echo "REMOTE_ADDR</br>";
5 var_dump($_SERVER['REMOTE_ADDR']);
6 echo "</br>";
7 echo "env_REMOTE_ADDR</br>";
8 var_dump(getenv('REMOTE_ADDR'));
9 echo "</br>";
10 echo "env_HTTP_CLIENT_IP</br>";
11 var_dump(getenv('HTTP_CLIENT_IP'));
12 echo "</br>";
13 echo "HTTP_CLIENT_IP</br>";
14 var_dump($_SERVER['HTTP_CLIENT_IP']);
15 echo "</br>";
16 echo "HTTP_X_FORWARDED_FOR</br>";
17 var_dump($_SERVER['HTTP_X_FORWARDED_FOR']);
18 echo "</br>";
19 echo "HTTP_X_FORWARDED</br>";
20 var_dump($_SERVER['HTTP_X_FORWARDED']);
21 echo "</br>";
22 echo "HTTP_X_CLUSTER_CLIENT_IP</br>";
23 var_dump($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']);
24 echo "</br>";
25 echo "HTTP_FORWARDED_FOR</br>";
26 var_dump($_SERVER['HTTP_FORWARDED_FOR']);
27 echo "</br>";
28 echo "HTTP_FORWARDED</br>";
29 var_dump($_SERVER['HTTP_FORWARDED']);
30 echo "</br>";
31
32 ?>

假设这个服务地址为http://xxx.xxx.xxx.xxx/apps/proxydetect.php
那么pipelines的代码如下

1 # Define your item pipelines here
2 # Don't forget to add your pipeline to the ITEM_PIPELINES setting
3 # See: http://doc.scrapy.org/topics/item-pipeline.html
4 from scrapy.exceptions import DropItem
5 import re
6 import urllib
7 import urllib2
8 import time
9 import exceptions
10 import socket
11 class ProxyPipeline(object):
12 def process_item(self, item, spider):
13 port = item['port']
14 port_re = re.compile('\d{1,5}')
15 ports = port_re.findall(port)
16 if len(ports) == 0:
17 raise DropItem("can not find port in %s" % item['port'])
18 else:
19 item['port'] = ports[0]
20 #profiling the proxy
21 #detect_service_url = 'http://xxx.xxx.xxx.xxx:pppp/apps/proxydetect.php'
22 detect_service_url = 'http://xxx.xxx.xxx.xxx/apps/proxydetect.php'
23 local_ip = 'xxx.xxx.xxx.xxx'
24 proxy_ = str('http://%s:%s' % (str(item['address']), str(item['port'])))
25 proxies = {'http':proxy_}
26 begin_time = time.time()
27 timeout = 1
28 socket.setdefaulttimeout(timeout)
29 try:
30 data = urllib.urlopen(detect_service_url, proxies=proxies).read()
31 except exceptions.IOError:
32 raise DropItem("curl download the proxy %s:%s is bad" % (item['address'],str(item['port'])))
33
34 end_time = time.time()
35 if '' == data.strip():
36 raise DropItem("data is null the proxy %s:%s is bad" % (item['address'],str(item['port'])))
37 if data.find('PROXYDETECTATION') == -1:
38 raise DropItem("wrong response the proxy %s:%s is bad" % (item['address'],str(item['port'])))
39 if data.find('PROXYDETECTATION') != -1:
40 if data.find(local_ip) == -1:
41 item['type'] = 'anonymity'
42 else:
43 item['type'] = 'nonanonymity'
44 item['delay'] = str(end_time - begin_time)
45 item['timestamp'] = time.strftime('%Y-%m-%d',time.localtime(time.time()))
46
47 #record the item info
48 fp = open('/home/xxx/services_runenv/crawlers/proxy/proxy/data/proxies.txt','a')
49 line = str(item['timestamp']) + '\t' + str(item['address']) + '\t' + str(item['port']) + '\t' + item['type'] + '\t' + str(item['delay']) + '\n'
50 fp.write(line)
51 fp.close()
52 return item

其中local_ip为抓取服务器本机的ip地址
4. 最后一个要说的就是setting.py配置文件,大家看具体代码吧

1 # Scrapy settings for proxy project
2 #
3 # For simplicity, this file contains only the most important settings by
4 # default. All the other settings are documented here:
5 #
6 # http://doc.scrapy.org/topics/settings.html
7 #
8
9 BOT_NAME = 'proxy'
10 BOT_VERSION = '1.0'
11
12 SPIDER_MODULES = ['proxy.spiders']
13 NEWSPIDER_MODULE = 'proxy.spiders'
14 USER_AGENT = '%s/%s' % (BOT_NAME, BOT_VERSION)
15
16 DOWNLOAD_DELAY = 0
17 DOWNLOAD_TIMEOUT = 30
18
19 ITEM_PIPELINES = [
20 'proxy.pipelines.ProxyPipeline'
21 ]
22 CONCURRENT_ITEMS = 100
23 CONCURRENT_REQUESTS_PER_SPIDER = 64
24 CONCURRENT_SPIDERS = 128
25
26 LOG_ENABLED = True
27 LOG_ENCODING = 'utf-8'
28 LOG_FILE = '/home/xxx/services_runenv/crawlers/proxy/proxy/log/proxy.log'
29 LOG_LEVEL = 'DEBUG'
30 LOG_STDOUT = False

最后秀一下抓取到的代理ip数据
好了,这篇就这些,下一篇将介绍如果使用代理ip作为媒介,放心的去大规模抓取网站数据,晚安。
【scrapy】使用方法概要(三)(转)的更多相关文章
- 编写高质量JS代码的68个有效方法(三)
[20141030]编写高质量JS代码的68个有效方法(三) *:first-child { margin-top: 0 !important; } body>*:last-child { ma ...
- scrapy爬虫学习系列三:scrapy部署到scrapyhub上
系列文章列表: scrapy爬虫学习系列一:scrapy爬虫环境的准备: http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_python_00 ...
- python练习题-简单方法判断三个数能否组成三角形
python简单方法判断三个数能否组成三角形 #encoding=utf-8 import math while True: str=raw_input("please input thre ...
- Python3 Scrapy 安装方法
Python3 Scrapy 安装方法 (一脸辛酸泪) 写在前面 最近在学习爬虫,在熟悉了Python语言和BeautifulSoup4后打算下个爬虫框架试试. 没想到啊,这坑太深了... 看了看相关 ...
- centos LB负载均衡集群 三种模式区别 LVS/NAT 配置 LVS/DR 配置 LVS/DR + keepalived配置 nginx ip_hash 实现长连接 LVS是四层LB 注意down掉网卡的方法 nginx效率没有LVS高 ipvsadm命令集 测试LVS方法 第三十三节课
centos LB负载均衡集群 三种模式区别 LVS/NAT 配置 LVS/DR 配置 LVS/DR + keepalived配置 nginx ip_hash 实现长连接 LVS是四层LB ...
- js replace 全局替换 以表单的方式提交参数 判断是否为ie浏览器 将jquery.qqFace.js表情转换成微信的字符码 手机端省市区联动 新字体引用本地运行可以获得,放到服务器上报404 C#提取html中的汉字 MVC几种找不到资源的解决方式 使用Windows服务定时去执行一个方法的三种方式
js replace 全局替换 js 的replace 默认替换只替换第一个匹配的字符,如果字符串有超过两个以上的对应字符就无法进行替换,这时候就要进行一点操作,进行全部替换. <scrip ...
- List的remove()方法的三种正确打开方式
转: java编程:List的remove()方法的三种正确打开方式! 2018年08月12日 16:26:13 Aries9986 阅读数 2728更多 分类专栏: leetcode刷题 版权声 ...
- uni-app&H5&Android混合开发三 || uni-app调用Android原生方法的三种方式
前言: 关于H5的调用Android原生方法的方式有很多,在该片文章中我主要简单介绍三种与Android原生方法交互的方式. 一.H5+方法调用android原生方法 H5+ Android开发规范官 ...
- Python 数据类型常用的内置方法(三)
目录 Python 数据类型常用的内置方法(三) 1.列表内置方法 1.sort():升序 2.reverse():颠倒顺序 3.列表比较运算 2.字典内置方法 1.对Key的操作 2.len( )- ...
随机推荐
- 利用vw+rem实现移动web适配布局
基本概念 1.单位 Px(CSS pixels) 像素 (px) 是一种绝对单位(absolute units), 因为无论其他相关的设置怎么变化,像素指定的值是不会变化的 其实是相对于某个设备而言的 ...
- TDictionary 与 TObjectDictionary
TDictionary 与 TObjectDictionary 的区别是 : TObjectDictionary 可以做到 free的时候 里面的对象 一并free,从而不会出现内存 泄露. 用途: ...
- 虚拟机的安装以及Linux的学习
安装虚拟机 对虚拟机的认识 其实初中的时候我就听说过虚拟机这个名词,当时的我还小,也不知道虚拟机是个什么东西,那时我傻傻的认为虚拟机只不过是电脑中的一个虚拟的计算机,没有什么实在的作用.后来随着大学课 ...
- HttpService与WebService的差异
httpservice通过post和get得到你想要的东西webservice就是使用soap协议得到你想要的东西,相比httpservice能处理些更加复杂的数据类型 当你要调用一个你本服务的内容的 ...
- sql server2014 企业版 百度云下载
sql server2014 企业版 百度云下载 链接: https://pan.baidu.com/s/1j7a6RWwpvSzG-sF7Dnexfw 提取码: 关注公众号[GitHubCN]回复获 ...
- drools7 (三、kmodule 介绍)
注意几点: 1. kmodule 有默认的加载路径, 看 KieModuleModelImpl 这个类的源代码 public class KieModuleModelImpl implements ...
- USACO 6.2 Packing Rectangles
Packing RectanglesIOI 95 The six basic layouts of four rectangles Four rectangles are given. Find th ...
- TestNG入门到...
目录 一.概述 二.@Test注解常用参数 三.测试中常用的断言(assert) 四.TestNG常用注解及使用 五.配置文件xml常用标签 六.参数传递 七.测试报告 一.概述 1.TestNG是一 ...
- Jersey入门一:从Maven Archetype创建jersey项目
1.用Ctrl+空格调出Spotlight搜索,输入ter调出终端窗口  2.在终端窗口进入将创建jersey项目的目录:  3.输入如下命令,创建一个名为的simple-service项目: m ...
- centos7 安装 supervisor
一.安装 supervisor yum install python-setuptools easy_install supervisor 如果easy_install不好使就从官方下载: wget ...