scrapy写第一个爬虫

本节示例以爬取西刺免费代理网站为例( http://www.xicidaili.com ),说明用scrapy框架写一个爬虫的基本流程。其中已实现mysql存储。

简易爬虫编写

1. 新建一个工程

scrapy startproject xici

生成如下目录:

1
2
3
4
5
6
7
8
9
10

xici
scrapy.cfg
xici
__init__.py
items.py
pipelines.py
settings.py
spiders
__init__.py

2. 生成一个spider

进入xici项目目录,使用命令生成一个spider

`scrapy genspider xiciSpider xicidaili.com` //生成一个爬取域名xicidaili.com,名字为xiciSpider的spider

目录结构如下:
1
2
3
4
5
6
7
8
9
10
11

xici
scrapy.cfg
xici
__init__.py
items.py
pipelines.py
settings.py
spiders
__init__.py
xiciSpider.py //新增文件

3. 编写item

在items.py中XiciItem类中加入以下信息

1
2
3
4
5
6
7
8
9
10

class XiciItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
ip = scrapy.Field()
port = scrapy.Field()
location = scrapy.Field()
anonymous = scrapy.Field()
pro_type = scrapy.Field()#是HHTP链接还是HTTPS链接
verify_time = scrapy.Field()

4. 编写spider

在xiciSpider.py中新增以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# -*- coding: utf-8 -*-
import scrapy
from scrapy.selector import Selector
from xici.items import XiciItem

class XicispiderSpider(scrapy.Spider):
name = "xiciSpider"
allowed_domains = ["xicidaili.com"]
start_urls = (
'http://www.xicidaili.com/nn/',
'http://www.xicidaili.com/nt/'
)

def parse(self, response):
sel=Selector(response)
items = []
flag = 0;
trs = sel.xpath('//*[@id="ip_list"]/tr')
for i in range(1,len(trs)):
item = XiciItem()
tr = trs[i]
item['ip'] = tr.xpath("td[3]/text()").extract()
item['port'] = tr.xpath("td[4]/text()").extract()
item['location'] = tr.xpath("td[5]/a/text()").extract() and \
tr.xpath("td[5]/a/text()").extract() or tr.xpath("td[5]/text()").extract() #不同页面获取location的xpath不同
item['anonymous'] = tr.xpath("td[6]/text()").extract()
item['pro_type'] = tr.xpath("td[7]/text()").extract()
item['verify_time'] = tr.xpath("td[10]/text()").extract()
items.append(item)
return items
- `name`: Spider的标识。它必须是唯一的, 那就是说,你不能在不同的Spiders中设置相同的名字。
- `start_urls`:Spider将会去爬这些URLs的列表。所以刚开始的下载页面将要包含在这些列表中。其他子URL将会从这些起始URL中继承性生成。
- `parse()`:每一个URL爬取完成默认调用的处理函数, 这个方法负责解析response数据和提出抓取的数据(作为抓取的items)。

5. 运行爬虫

输入以下命令进行文件爬取

`scrapy crawl xiciSpider //运行爬虫`

`scrapy crawl xiciSpider -o ips.json //将提取的结果以json格式(自动转换)存储到ips.json文件中`

> scrapy 内置支持如下格式: 'xml', 'jl', 'json', 'jsonlines', 'csv', 'pickle', 'marshal'

将爬取的内容存储到数据库

本示例以mysql为例

1. pipeline编写

在pipeline.py中加入数据库存储的相关代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
	
# -*- 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

from scrapy import log
from twisted.enterprise import adbapi
from scrapy.http import Request
import json
import codecs
import MySQLdb
import MySQLdb.cursors

class XiciPipeline(object):
def process_item(self, item, spider):
return item

class MySQLStoreIPPipeline(object):
def __init__(self):
self.dbpool = adbapi.ConnectionPool('MySQLdb',
host = '127.0.0.1', #settings['MYSQL_HOST'],
port = 3306,
db = 'agent_ip', #settings['MYSQL_DBNAME'],
user = 'root',#settings['MYSQL_USER'],
passwd = 'root',#settings['MYSQL_PASSWD'],
cursorclass = MySQLdb.cursors.DictCursor,
charset = 'utf8',
use_unicode = True
)

def process_item(self, item, spider):
query = self.dbpool.runInteraction(self._conditional_insert, item,spider)
query.addErrback(self.handle_error)
return item

def _conditional_insert(self,tx,item,spider):
tx.execute("select * from ips where ip= %s",(item['ip'][0],))
result=tx.fetchone()
log.msg(result)
if result:
log.msg("Item already stored in db:%s" % item,level=log.DEBUG)
else:
tx.execute("insert into ips (ip,port,location,anonymous,pro_type,verify_time) values (%s,%s,%s,%s,%s,%s)",\
(item['ip'][0],item['port'][0],item['location'][0],item['anonymous'][0],item['pro_type'][0],item['verify_time'][0]))
log.msg("Item stored in db: %s" % item, level=log.DEBUG)

def handle_error(self, e):
log.err(e)
> 以上代码中定义了类MySQLStoreIPPipeline,调用该pipeline时会自动调用其`process_item`方法

> 每个item pipeline组件都需要调用`process_item`方法,这个方法必须返回一个 Item (或任何继承类)对象, 或是抛出 DropItem 异常,被丢弃的item将不会被之后的pipeline组件所处理。

2. 配置settings.py文件

在settings.py中加入如下配置

1
2
3
ITEM_PIPELINES = {
'xici.pipelines.MySQLStoreIPPipeline':300
}
> 以上配置是显示声明调用MySQLStoreIPPipeline,如果不加入该项配置,即使在pipeline.py中定义了该类,spider也不会调用
> 
> 类后面的整型值,确定了其运行的顺序,item按数字从低到高的顺序,通过pipeline,通常将这些数字定义在0-1000范围内
文章目录
  1. 1. 简易爬虫编写
    1. 1.1. 1. 新建一个工程
    2. 1.2. 2. 生成一个spider
    3. 1.3. 3. 编写item
    4. 1.4. 4. 编写spider
    5. 1.5. 5. 运行爬虫
  2. 2. 将爬取的内容存储到数据库
    1. 2.1. 1. pipeline编写
    2. 2.2. 2. 配置settings.py文件