请初学者作为参考,不建议高手看这个浪费时间】

前两篇大概讲述了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作为媒介,放心的去大规模抓取网站数据,晚安。

喜欢一起简单,实用的东西,拒绝复杂花哨,我不是GEEK.

【scrapy】使用方法概要(三)(转)的更多相关文章

  1. 编写高质量JS代码的68个有效方法(三)

    [20141030]编写高质量JS代码的68个有效方法(三) *:first-child { margin-top: 0 !important; } body>*:last-child { ma ...

  2. scrapy爬虫学习系列三:scrapy部署到scrapyhub上

    系列文章列表: scrapy爬虫学习系列一:scrapy爬虫环境的准备:      http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_python_00 ...

  3. python练习题-简单方法判断三个数能否组成三角形

    python简单方法判断三个数能否组成三角形 #encoding=utf-8 import math while True: str=raw_input("please input thre ...

  4. Python3 Scrapy 安装方法

    Python3 Scrapy 安装方法 (一脸辛酸泪) 写在前面 最近在学习爬虫,在熟悉了Python语言和BeautifulSoup4后打算下个爬虫框架试试. 没想到啊,这坑太深了... 看了看相关 ...

  5. 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 ...

  6. js replace 全局替换 以表单的方式提交参数 判断是否为ie浏览器 将jquery.qqFace.js表情转换成微信的字符码 手机端省市区联动 新字体引用本地运行可以获得,放到服务器上报404 C#提取html中的汉字 MVC几种找不到资源的解决方式 使用Windows服务定时去执行一个方法的三种方式

    js replace 全局替换   js 的replace 默认替换只替换第一个匹配的字符,如果字符串有超过两个以上的对应字符就无法进行替换,这时候就要进行一点操作,进行全部替换. <scrip ...

  7. List的remove()方法的三种正确打开方式

    转: java编程:List的remove()方法的三种正确打开方式! 2018年08月12日 16:26:13 Aries9986 阅读数 2728更多 分类专栏: leetcode刷题   版权声 ...

  8. uni-app&H5&Android混合开发三 || uni-app调用Android原生方法的三种方式

    前言: 关于H5的调用Android原生方法的方式有很多,在该片文章中我主要简单介绍三种与Android原生方法交互的方式. 一.H5+方法调用android原生方法 H5+ Android开发规范官 ...

  9. Python 数据类型常用的内置方法(三)

    目录 Python 数据类型常用的内置方法(三) 1.列表内置方法 1.sort():升序 2.reverse():颠倒顺序 3.列表比较运算 2.字典内置方法 1.对Key的操作 2.len( )- ...

随机推荐

  1. samba和SELINUX 冲突

    在使用Samba进行建立Window与Linux共享时,要是不能访问,出现“您可能没有权限使用网络资源”. setsebool -P samba_enable_home_dirs on setsebo ...

  2. 27 Debugging Go Code with GDB 使用GDB调试go代码

    Debugging Go Code with GDB  使用GDB调试go代码 Introduction Common Operations Go Extensions Known Issues Tu ...

  3. springboot配置fastjson后端往前端传输格式化

    import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.Spri ...

  4. Es官方文档整理-3.Doc Values和FieldData

    Es官方文档整理-3.Doc Values和FieldData 1.Doc Values 聚合使用一个叫Doc Values的数据结构.Doc Values使聚合更快.更高效且内存友好. Doc Va ...

  5. chmod g+s 、chmod o+t 、chmod u+s:Linux高级权限管理

    关于linux下权限操作chmod的一些说明!比rxw高级内容! 转载自http://blog.chinaunix.net/uid-26642180-id-3378119.html Set uid, ...

  6. Ubuntu下编译安装OpenCV 2.4.7并读取摄像头

    主要参考: 1.http://www.ozbotz.org/opencv-installation/ 2.http://www.ozbotz.org/opencv-install-troublesho ...

  7. ajax传递的参数服务器端接受不到的原因

    最常见的就是组织的json数据格式有问题,尝试把单引号改为双引号试试,如下: $datares = {"uname":$uname.val(),"phone": ...

  8. awk调用shell命令的两种方法:system与print

    from:http://www.oklinux.cn/html/developer/shell/20070626/31550.htmlawk中使用的shell命令,有2种方法: 一.使用所以syste ...

  9. elastucasearch基础理论以及安装

    一.elasticasearch核心概念 Near Realtime(NRT 近实时) Elasticsearch 是一个近实时的搜索平台.您索引一个文档开始直到它被查询时会有轻微的延迟时间(通常为1 ...

  10. vwware虚拟机无法连接外网

    1.问题:动态IP时连接外网没有问题,但是将IP改为静态IP时发现没有办法连接外网 查看文件/etc/resolv.conf,里面的内容全部都被注释 [root@jenkins network-scr ...