Scrapy入门教程:http://scrapy-chs.readthedocs.io/zh_CN/latest/intro/tutorial.html#
原文地址:http://python.jobbole.com/87284/
一、入门程序
1.准备工作:
Python
scrapy
python编辑器(IDE)
2.创建项目:
scrapy startproject xx
在cmd中运行上面命令,xx为项目的名称;
可以先进入要存放项目的文件夹(如:D:\py_project)中,然后按住Shift+鼠标右键->选择 在此处打开命令窗口
或 在cmd中 运行:
D:
cd /py_project
scrapy startproject xx
随后你会得到一个由scrapy创建的目录结构,且存放在py_project文件夹中
3.编写爬虫
在spiders文件夹中创建一个python文件,比如miao.py,来作为爬虫的脚本。
内容如下:
# -*- coding:utf-8 -*-
import scrapy
class XiaoHuarSpider(scrapy.Spider):
# 唯一定位实例的属性,必须唯一,运行时需要用到
name = "xiaohuar"
# 搜索的域名范围,也就是爬虫的约束区域,规定爬虫只爬取这个域名下的网页
allowed_domains = ["http://www.xiaohuar.com"]
# 爬取入口网页
start_urls = [
"http://www.xiaohuar.com/list-1-0.html",
]
# 这个是解析函数,如果不特别指明的话,scrapy抓回来的页面会由这个函数进行解析。
def parse(self, response):
# 把页面内容打印出来
print response.body
4.运行
在cmd命令行中运行:
D:
cd /py_project/miao
scrapy crawl xiaohuar
如果用的是pycharm IDE的话,可以点击页面底部的 Terminal 后输入: scrapy crawl xiaohuar
5.查看结果
如果结果中有输出我们爬取的html代码说明这个简单的爬虫页面获取成功了。
二、解析
接下来我们要把刚刚抓下来的页面进行分析,从混乱的html和js堆里把我们需要的内容提取出来。
目标:http://www.xiaohuar.com/list-1-0.html页面中校花图片的url
1.分析页面代码结构
分析http://www.xiaohuar.com/list-1-0.html页面中的校花图片代码结构,建议用Chrome浏览器打开,按F12查看页面结构
可以看到 图片所在的代码块是有规律的;如,每张图片都是在下面的<a>标签中
<div class="item masonry_brick masonry-brick" >
<div class="item_t">
<div class="img">
<a><img></a>
我们获取每张个<a>标签下的<img>的src就达到目的了
2.代码实现
在最上面加上引用:
from scrapy import Selector
把parse函数改成:
def parse(self, response):
selector = Selector(response)
# 这个list里的每一个元素都是我们要找的目标标签
content_list = selector.xpath("//div[@class='img']/a/img")
# 遍历这个list,处理每一个标签
for content in content_list:
# 此处解析标签,提取出我们需要的url地址
host = "".join(self.allowed_domains) //把list类型转为str类型
url = host + content.xpath('@src').extract_first()
print url
再次输入: scrapy crawl xiaohuar 运行后就可以看到第一页展示图片详情url了。
递归
接下来我们要抓取每一个图片下的内容;需要用到python的yield。
此处会告诉scrapy去抓取这个url,然后把抓回来的页面用指定的parse_content函数进行解析。
yield Request(url=url, callback=self.parse_content)
至此我们需要定义一个新的函数来分析一个图片里的内容
完整的代码如下:
# -*- coding:utf-8 -*-
from scrapy.spiders import Spider
from scrapy import Selector
from scrapy import Request
class XiaoHuarSpider(Spider):
name = "xiaohuar"
allowed_domains = ["http://www.xiaohuar.com"]
start_urls = [
"http://www.xiaohuar.com/list-1-0.html",
]
# 爬虫的入口,可以在此进行一些初始化工作,比如从某个文件或者数据库读入起始url
def start_requests(self):
for url in self.start_urls:
# 此处会告诉scrapy去抓取这个url,然后把抓回来的页面用指定的parse函数进行解析。
yield Request(url=url, callback=self.parse_url)
def parse_url(self, response):
selector = Selector(response)
# 这个list里的每一个元素都是我们要找的html标签
img_list = selector.xpath("//div[@class='img']/a")
print len(img_list)
# 遍历这个list,处理每一个标签
for content in img_list:
# 提取出img的url地址。
img_url = content.xpath('@href').extract_first()
print img_url
yield Request(url=img_url, callback=self.parse_content, dont_filter=True)
def parse_content(self, response):
selector = Selector(response)
content_list = selector.xpath("//div[@class='p-tmb']/a/img")
host = "".join(self.allowed_domains)
print len(content_list)
for content in content_list:
content_url = host + content.xpath('@src').extract_first()
print content_url
再次输入: scrapy crawl xiaohuar 运行后就可以看到第一页所有图片下的url了。
Pipelines——管道
此处是对已抓取、解析后的内容的处理,可以通过管道写入本地文件、数据库
1.定义Item
在miao文件夹中找到items.py文件
from scrapy import Item, Field
class UrlItem(Item):
img_link = Field()
class ContentItem(Item):
content_url = Field()
content_name = Field()
content_school = Field()
此处我们定义了两个简单的class来描述我们爬取的结果。
2.写一个处理方法
在miao文件夹下面找到那个pipelines.py文件,scrapy之前应该已经自动生成好了。
import urllib
class TutorialPipeline(object):
def open_spider(self, spider):
# 开始的时候执行,在这个函数中我们一般会连接数据库,为数据存储做准备
pass
def process_item(self, item, spider):
# 捕捉到item的时候执行,一般我们会在这里做数据过滤并且把数据存入数据库
if item['content_url']:
url = item['content_url']
path_name = url[-8:]
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) \
AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/35.0.1916.114 Safari/537.36',
'Cookie': 'AspxAutoDetectCookieSupport=1'
}
request = urllib2.Request(url, None, header)
response = urllib2.urlopen(request)
f = open("D:\imgs\%s.jpg" % path_name, "wb")
f.write(response.read())
f.close()
return item
def close_spider(self, spider):
# 在spider结束的时候执行,一般用来断开数据库连接或者做数据收尾工作
pass
3.在爬虫中调用这个处理方法。
要调用这个方法我们只需在爬虫中调用即可,例如原先的内容处理函数可改为:
from tutorial.items import UrlItem, ContentItem
def parse_content(self, response):
selector = Selector(response)
content_list = selector.xpath("//div[@class='p-tmb']/a/img")
host = "".join(self.allowed_domains)
print len(content_list)
for content in content_list:
# 创建个ContentItem对象把我们爬取的东西放进去
item = ContentItem()
# 相册图片url
item['content_url'] = host + content.xpath("//div[@class='infoleft_imgdiv']/a/img/@src").extract_first()
# 姓名
item['content_name'] = content.xpath("//div[@class='infodiv']/table/tbody/tr[1]/td[2]/text()").extract_first()
# 学校
item['content_school'] = content.xpath("//div[@class='infodiv']/table/tbody/tr[5]/td[2]/text()").extract_first()
# scrapy会把这个item交给我们刚刚写的FilePipeline来处理
yield item
4. 实现爬取多个页面
# -*- coding:utf-8 -*-
from scrapy.spiders import Spider
from scrapy import Selector
from scrapy import Request
from tutorial.items import ContentItem
class XiaoHuarSpider(Spider):
name = "xiaohuar"
# host = "http://www.xiaohuar.com"
allowed_domains = ["http://www.xiaohuar.com"]
start_urls = [
"http://www.xiaohuar.com/list-1-0.html",
]
# 爬虫的入口,可以在此进行一些初始化工作,比如从某个文件或者数据库读入起始url
def start_requests(self):
# re_url = " http://www.xiaohuar\.com/p-1-\d +\.html"
urls = self.start_urls
# 定义要爬取的页面
for x in range(1, 5):
urls.append("http://www.xiaohuar.com/list-1-%d.html" % x)
for url in urls:
# 此处会告诉scrapy去抓取这个url,然后把抓回来的页面用指定的parse函数进行解析。
yield Request(url=url, callback=self.parse_url)
def parse_url(self, response):
selector = Selector(response)
# 这个list里的每一个元素都是我们要找的html标签
img_list = selector.xpath("//div[@class='img']/a")
print len(img_list)
# 遍历这个list,处理每一个标签
for content in img_list:
# 提取出img的url地址。
img_url = content.xpath('@href').extract_first()
print img_url
yield Request(url=img_url, callback=self.parse_content, dont_filter=True)
def parse_content(self, response):
selector = Selector(response)
content_list = selector.xpath("//div[@class='res_infobox clearfix']")
host = "".join(self.allowed_domains)
for content in content_list:
# 创建个ContentItem对象把我们爬取的东西放进去
item = ContentItem()
# 相册图片url
item['content_url'] = host + content.xpath("//div[@class='infoleft_imgdiv']/a/img/@src").extract_first()
# 姓名
item['content_name'] = content.xpath("//div[@class='infodiv']/table/tbody/tr[1]/td[2]/text()").extract_first()
# 学校
item['content_school'] = content.xpath("//div[@class='infodiv']/table/tbody/tr[5]/td[2]/text()").extract_first()
# scrapy会把这个item交给我们刚刚写的FilePipeline来处理
yield item
5.在配置文件里指定这个pipeline
找到settings.py文件,在里面加入:
ITEM_PIPELINES = {
'miao.pipelines.FilePipeline': 400,
}
这样在爬虫里调用 yield item 的时候都会由经这个FilePipeline来处理。后面的数字400表示的是优先级。
可以在此配置多个Pipeline,scrapy会根据优先级,把item依次交给各个item来处理,每个处理完的结果会传递给下一个pipeline来处理。
可以这样配置多个pipeline,如:
ITEM_PIPELINES = {
'miao.pipelines.Pipeline00': 400,
'miao.pipelines.Pipeline01': 401,
'miao.pipelines.Pipeline02': 402,
'miao.pipelines.Pipeline03': 403,
## ...
}
Middleware——中间件
通过Middleware我们可以对请求信息作出一些修改,比如常用的设置UA、代理、登录信息等等都可以通过Middleware来配置。
1.Middleware的配置
与pipeline的配置类似,在setting.py中加入Middleware的名字,例如
DOWNLOADER_MIDDLEWARES = {
"miao.middleware.UserAgentMiddleware": 401,
"miao.middleware.ProxyMiddleware": 402,
}
2.破网站查UA, 我要换UA
某些网站不带UA是不让访问的。
在miao文件夹下面找到middleware.py
import random
def process_request(self, request, spider):
agents = [
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5",
"Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.310.0 Safari/532.9",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.514.0 Safari/534.7",
"Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/10.0.601.0 Safari/534.14",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1",
]
agent = random.choice(agents)
request.headers["User-Agent"] = agent
这里就是一个简单的随机更换UA的中间件,agents的内容可以自行扩充。
3.破网站封IP,我要用代理
比如本地127.0.0.1开启了一个8123端口的代理,同样可以通过中间件配置让爬虫通过这个代理来对目标网站进行爬取。
同样在middleware.py中加入:
def process_request(self, request, spider):
# 此处填写你自己的代理
# 如果是买的代理的话可以去用API获取代理列表然后随机选择一个
proxy = "http://127.0.0.1:8123"
request.meta["proxy"] = proxy
很多网站会对访问次数进行限制,如果访问频率过高的话会临时禁封IP。
如果需要的话可以从网上购买IP,一般服务商会提供一个API来获取当前可用的IP池,选一个填到这里就好。
一些常用配置
在settings.py中的一些常用配置
# 间隔时间,单位秒。指明scrapy每两个请求之间的间隔。
DOWNLOAD_DELAY = 5
# 当访问异常时是否进行重试
RETRY_ENABLED = True
# 当遇到以下http状态码时进行重试
RETRY_HTTP_CODES = [500, 502, 503, 504, 400, 403, 404, 408]
# 重试次数
RETRY_TIMES = 5
# Pipeline的并发数。同时最多可以有多少个Pipeline来处理item
CONCURRENT_ITEMS = 200
# 并发请求的最大数
CONCURRENT_REQUESTS = 100
# 对一个网站的最大并发数
CONCURRENT_REQUESTS_PER_DOMAIN = 50
# 对一个IP的最大并发数
CONCURRENT_REQUESTS_PER_IP = 50