如何将request模块和scrapy yield request框架配合使用

如何快速学习爬虫框架Scrapy?神级程序员整理了一些最重要的资料
如何快速学习爬虫框架Scrapy?神级程序员整理了一些最重要的资料
今天咱们就来花几分钟了解一下Python爬虫好玩的地方吧!差点忘了。在给大家分享之前呢,小编推荐一下一个挺不错的交流宝地,里面都是一群热爱并在学习Python的小伙伴们,大几千了吧,各种各样的人群都有,特别喜欢看到这种大家一起交流解决难题的氛围,群资料也上传了好多,各种大牛解决小白的问题,这个Python群: 欢迎大家进来一起交流讨论,一起进步,尽早掌握这门Python语言。对于规模小、爬取数据量小、对爬取速度不敏感的爬虫程序, 使用 Requests 能轻松搞定。这些爬虫程序主要功能是爬取网页、玩转网页。如果我们需要爬取网站以及系列网站,要求爬虫具备爬取失败能复盘、爬取速度较高等特点。很显然 Requests 不能完全满足我们的需求。因此,需要一功能更加强大的第三方爬虫框架库 —— ScrapyHTML, XML源数据 选择及提取 的内置支持提供了一系列在spider之间共享的可复用的过滤器(即 Item Loaders),对智能处理爬取数据提供了内置支持。通过 feed导出 提供了多格式(JSON、CSV、XML),多存储后端(FTP、S3、本地文件系统)的内置支持提供了media pipeline,可以 自动下载 爬取到的数据中的图片(或者其他资源)。高扩展性。您可以通过使用 signals ,设计好的API(中间件, extensions, pipelines)来定制实现您的功能。内置的中间件及扩展为下列功能提供了支持:cookies and session 处理HTTP 压缩HTTP 认证HTTP 缓存user-agent模拟robots.txt爬取深度限制健壮的编码支持和自动识别,用于处理外文、非标准和错误编码问题针对多爬虫下性能评估、失败检测,提供了可扩展的 状态收集工具 。内置 Web service, 使您可以监视及控制您的机器。原因是 Twisted 底层是由 C 语言编写的,所以需要安装C语言的编译环境。对于Python3.5来说,可以通过安装 Visual C++ Build Tools 来安装这个环境。打开上面报错文本中的链接,下载并安装 visualcppbuildtools_full 。等安装完成,再执行安装 Scrapy 命令。安装成功之后如下图:2 初探 Scrapy2.1 Scrapy 项目解析Scrapy 新建项目需通过命令行操作。在指定文件夹中,打开终端执行以下命令:scrapy startproject 项目的名字我新建一个名为 scrapy_demo,执行结果如下。使用 Pycharm 打开该项目,我们会发现项目的层级架构以及文件。2.2 Scrapy 的架构我们刚接触到新事物,想一下子就熟悉它。这明显是天方夜谭。应按照一定的顺序层次、逐步深入学习。学习 Scrapy 也不外乎如此。在我看来,Scrapy 好比由许多组件拼装起来的大机器。因此,可以采取从整体到局部的顺序学习 Scrapy。下图是 Scrapy 的架构图,它能让我们对 Scrapy 有了大体地认识。后续的文章会逐个介绍其组件用法。我按照从上而下,从左往右的顺序阐述各组件的作用。2.3 Scrapy 工作机制我们对 Scrapy 有了大体上的认识。接下来我们了解下 Scrapy 内部的工作流程。同样先放出一张图,然后我再细细讲解。当引擎(Engine) 收到 Spider 发送过来的 url 主入口地址(其实是一个 Request 对象, 因为 Scrapy 内部是用到 Requests 请求库),Engine 会进行初始化操作。Engine 请求调度器(Scheduler),让 Scheduler 调度出下一个 url 给 Engine。Scheduler 返回下一个 url 给 Engine。Engine 将 url通过下载中间件(请求(request)方向)转发给下载器(Downloader)。一旦页面下载完毕,Downloader 生成一个该页面的Response,并将其通过下载中间件(返回(response)方向)发送给 Engine引擎将从下载器中接收到 Response 发送给Spider处理。Spider 处理 Response 并返回爬取到的 Item 及新的 Request 给引擎。Engine 将 Spider 返回的爬取到的 Item 转发给Item Pipeline,顺便也将将 Request 给调度器。重复(第2步)直到调度器中没有更多地request,引擎关闭该网站。谢谢阅读 ,本文转载于,
本文仅代表作者观点,不代表百度立场。系作者授权百家号发表,未经许可不得转载。
百家号 最近更新:
简介: 健康积极的生活,来自不断地分享与学习
作者最新文章scrapy框架的使用
一。scrapy框架的使用
写了一大堆,没有保存。不想再写了
二。代理的使用
在爬数据的时候,经常会出现IP被封的问题。(携程是直接封IP的网络号,蚂蜂窝是要输入验证码)。所以是引入了代理的使用。
使用有代理IP,网址:/得到一些国外的IP。这些代理还需验证,使用的是online
checker,网址:http://www.checker.freeproxy.ru/checker/。进行验证。得到一些有效的代理,并将代理写入服务器。写了一个.py文件,用来把数据库的代理写成了JSON文件。
import json
import MySQLdb
def getProxyJson():
conn = MySQLdb.connect(host='127.0.0.1',
#@UndefinedVariable
user='root',
passwd='123',
db='plan',
charset='utf8')
cursor = conn.cursor()
SQL_string = 'select ip from proxy'
cursor.execute(SQL_string)
proxys=cursor.fetchall()
proxy_list=[]
for it in proxys:
proxy_list.append(it[0])
with open('proxy.json','w')as file:
file.write(json.dumps(proxy_list))
在Scrapy中使用代理:
open('proxy.json', 'r')as file:
& t = file.readline()
& proxy_list = json.loads(t)
& i = random.randint(0, len(proxy_list) -
&Max_Request_Nums =
& yield Request(url="/",
callback=self.parse_city,
& & meta={'proxy': "http://%s" %
proxy_list[i], 'proxy_list': proxy_list,
& & 'Max_Request_nums':
Max_Request_Nums}, errback=self.SetProxy(Max_Request_Nums))
这里面使用到JSON,使用到json.dumps(***),json.loads(***).json.dumps()把python对象编码成JSON字符串,json.loads()把JSON字符串编码成python对象。读json文件,在文件随机选择一个代理IP,用来请求服务器。
3.错误处理:
设置了errback错误回调函数,如果Request请求失败,怎随机在随机选择一个代理进行请求。并设置最多请求次数为5。
&def SetProxy(self,
Max_Request_Nums):
& & Max_Request_Nums =
Request.meta['Max_Request_nums']
& & Max_Request_Nums =
Max_Request_Nums - 1
& & if Max_Request_Nums &
& with open('proxy.json', 'r')as
file.readline()
& & & proxy_list
= json.loads(t)
random.randint(0, len(proxy_list) - 1)
& yield Request(url="/",
callback=self.parse_city,
& & meta={'proxy': "http://%s" %
proxy_list[i], 'proxy_list': proxy_list},
errback=self.SetProxy(Max_Request_Nums))
4.爬虫代码上传到服务器
这个就可以是用PYCharm中的TOOLS的Deloyment,配置中,建立连接、本地和远程服务器的映射。然后进行upload就可以了。之后改进后进行sync同步即可。
在PYCharm中也可以建立SSH session。在这里注意,lxp中的SSH
session采用都是密钥验证。之后在服务器中运行程序即可。其中出现一个问题,Import
Error,找不到引用的spider。这里主要是设置路径问题。解决方法一:在程序中写入系统运行的变量
import sys
sys.path.append('.')
即把当前路径加入到python运行的坏境
运行时在home\xiaonuanhu\mafengwo 下进行运行
解决办法二:
在用户的配置文件中进行配置,即在.profile中写:
export PYTHONPATH=home\xiaonuan\mafengwo
同时运行也在home\xiaonuan\mafengwo运行即可
5.用screen来解决SSH会话中断的问题
当你建立一个SSH会话,并通过SSH会话运行服务器的程序时。运行的程序实际是在你的SSH进程建立了一个进程。所以当网络中断,SSH会话中断,就无法运行服务器程序。此时采用了Screen。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。本文是跟着大神博客,尝试从网站上爬一堆东西,一堆你懂得的东西
附上原创链接:
基本思路是,查看网页元素,填写xpath表达式,获取信息。自动爬取策略是,找到翻页网页元素,获取新链接地址,执行翻页。网页分析部分不再赘述,原博讲的很好很清楚,很涨姿势
基于拿来主义,我们只需要知道怎么更改Scrapy框架就行了~
import scrapy
class TestprojItem(scrapy.Item):
image_urls = scrapy.Field();
由于仅关注图片信息,所以这里item只定义了一个元素。
spider.py:
class FirstSpider(scrapy.Spider):
name = "jiandan"
allowed_domains = ["http://jiandan.net/ooxx"]
new_url = None
start_urls = [
"http://jiandan.net/ooxx"
def parse(self, response):
item = TestprojItem()
item['image_urls'] = response.xpath('//img//@src').extract()
#print "extracting..." + ''.join(item['image_urls'])
yield item
self.new_url = response.xpath('//a[@class="previous-comment-page"]//@href').extract_first()
print 'new_url:\t' + self.new_url
if self.new_url:
self.start_urls.append(self.new_url)
yield scrapy.Request(self.new_url, callback=self.parse, dont_filter=True)
回顾并强调一下本次任务的目标:简单上的妹子图片!
上面是我自己修改的代码,可能allowed_domains字段设置有问题,每次重新爬取的时候会被认为是非法,所以在代码最后一行加了个 dont_filter=True.
parse: 对爬取页面进行解析。其中,new_url是获取翻页请求地址,然后在最后一行scrapy.Request重新请求。
pipelines.py:
# -*- 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 urllib
from testProj import settings
class TestprojPipeline(object):
def process_item(self, item, spider):
dir_path = '%s%s' % (settings.IMAGES_STORE, spider.name)
print 'dir_path:', dir_path
if not os.path.exists(dir_path):
os.makedirs(dir_path)
for image_url in item['image_urls']:
list_name = image_url.split('/')
file_name = list_name[len(list_name)-1]
file_path = '%s%s'%(dir_path, file_name)
if os.path.exists(file_name):
with open(file_path, 'wb') as fw:
conn = urllib.urlopen(image_url)
fw.write(conn.read())
fw.close()
return item
对爬取的元素进行处理。本文直接放到某个本地文件夹中,所以最后有文件读写。
其中settings.IMAGES_STORE需要进入settings进行设置。另外,settings中的 ITEM_PIPLINES字段取消掉注释。
OK,基本完成。切入cmd, scrapy crawl jiandan  瞬间完成,进入文件夹,什么也没有啊?查看cmd输出信息
重定位到一个奇怪的url, 打开来看
我是小白,原来这就是被网站ban了。很多网站有反爬虫设置。如何突破?基本策略有以下几点:
动态设置user agent
禁用cookies
设置延迟下载
使用IP地址池(&&、VPN和代理IP)
好几条看不懂。我自己研究。浏览器再次打开简单网,能打开。说明需要伪装成浏览器想服务器发送请求。
工程下新建 middlewares.py文件,代码如下:
import random
class RandomUserAgent(object):
def __init__(self, agents):
self.agents = agents
@classmethod
def from_crawler(cls, crawler):
print 'in from crawler'
return cls(crawler.settings.getlist('USER_AGENTS'))
def process_request(self, request, spider):
print 'in process request'
request.headers.setdefault('User-Agent', random.choice(self.agents))
settings.py中做相应修改:
USER_AGENTS = [
"Mozilla/4.0 ( MSIE 6.0; Windows NT 5.1; SV1; AcooB .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
"Mozilla/4.0 ( MSIE 7.0; Windows NT 6.0; Acoo B SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",
#中间还有很多,这里省略了
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11",
"Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/ Ubuntu/10.10 (maverick) Firefox/3.6.10"
COOKIES_ENABLED = False
DOWNLOADER_MIDDLEWARES = {
'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware' : None,
'testProj.middlewares.RandomUserAgent': 100
这里&DOWNLOADER_MIDDLEWARES 字段的修改很重要,它相当于是定位到之前写的middlewares.py文件。注意一下,我是吧middlewares.py文件放在testProj项目根目录下,和items.py之类在一起,才这样写,如果其他目录,可能需要改变名称。(但是我放在testProj/middlewares/middlewares.py,setting里面写&testProj.middlewares.middlewares.RandomUserAgent依旧没用,不知道为什么,调了很久)
OK。大致完成
但是我发现下载了大概2000张图片之后又下不动了,整个Scrapy就卡在那儿,也不输出日志,不清楚什么原因,可能是需要加入ip代理,下次再来研究吧。
阅读(...) 评论()python爬虫----&scrapy框架提高&1&&自定义Request爬取&
最近看scrappy0.24官方文档看的正心烦的时候,意外发现中文翻译0.24文档,简直是福利呀~
结合官方文档例子,简单整理一下:
import scrapy
from myproject.items import MyItem
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = (
def parse(self, response):
# collect `item_urls`
for item_url in item_urls:
yield scrapy.Request(item_url, self.parse_item)
def parse_item(self, response):
item = MyItem()
# populate `item` fields
# and extract item_details_url
yield scrapy.Request(item_details_url, self.parse_details, meta={'item': item})
def parse_details(self, response):
item = response.meta['item']
# populate more `item` fields
return item
从Spider继承了一个爬虫类,唯一名称 name="myspider", 爬虫默认入口地址 start_urls = () ,元组或列表都可以。
从Spider源码中,可以看到:
# 代码片段
class Spider(object_ref):
"""Base class for scrapy spiders. All spiders must inherit from this
name = None
def __init__(self, name=None, **kwargs):
if name is not None:
self.name = name
elif not getattr(self, 'name', None):
raise ValueError("%s must have a name" % type(self).__name__)
self.__dict__.update(kwargs)
if not hasattr(self, 'start_urls'):
self.start_urls = []
在Spider初始化时,检查name是否为None,start_urls 是否存在。代码很简单
继续向下看:
# 代码片段
def start_requests(self):
for url in self.start_urls:
yield self.make_requests_from_url(url)
def parse(self, response):
raise NotImplementedError
到这里很容易看到, start_requests 方法,遍历 start_urls
中的url,并执行 Request请求
默认response处理方法入口,parse函数需要实现,也就是在继承类中重写parse方法。
再看,示例代码中。
# 第一个函数
def parse(self, response):
# collect `item_urls`
# 可以理解为:网站的所有导航菜单的超链接集合
for item_url in item_urls:
yield scrapy.Request(item_url, self.parse_item)
为默认入口,也就是从父类Spider类中继承过来的(或者说是一个必须要实现的接口),但是需要实现。
在这个函数体中,根据 start_requests (默认为GET请求)返回的 Response,得到了一个 名字为‘item_urls’ 的url集合。
然后遍历并请求这些集合。
再看 Request 源码:
# 部分代码
class Request(object_ref):
def __init__(self, url, callback=None, method='GET', headers=None, body=None,
cookies=None, meta=None, encoding='utf-8', priority=0,
dont_filter=False, errback=None):
self._encoding = encoding
# this one has to be set first
self.method = str(method).upper()
self._set_url(url)
self._set_body(body)
assert isinstance(priority, int), "Request priority not an integer: %r" % priority
self.priority = priority
assert callback or not errback, "Cannot use errback without a callback"
self.callback = callback
self.errback = errback
self.cookies = cookies or {}
self.headers = Headers(headers or {}, encoding=encoding)
self.dont_filter = dont_filter
self._meta = dict(meta) if meta else None
def meta(self):
if self._meta is None:
self._meta = {}
return self._meta
其中,比较常用的参数:
url: 就是需要请求,并进行下一步处理的url
callback: 指定该请求返回的Response,由那个函数来处理。
method: 一般不需要指定,使用默认GET方法请求即可
headers: 请求时,包含的头文件。一般不需要。内容一般如下:使用 urllib2 自己写过爬虫的肯定知道
Host: media.readthedocs.org
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:33.0) Gecko/ Firefox/33.0
Accept: text/css,*/*;q=0.1
Accept-Language: zh-cn,q=0.8,en-q=0.5,q=0.3
Accept-Encoding: gzip, deflate
Referer: http://scrapy-chs.readthedocs.org/zh_CN/0.24/
Cookie: _ga=GA1.2..;
Connection: keep-alive
If-Modified-Since: Mon, 25 Aug :35 GMT
Cache-Control: max-age=0
meta: 比较常用,在不同的请求之间传递数据使用的。字典dict型
request_with_cookies = Request(url="",
cookies={'currency': 'USD', 'country': 'UY'},
meta={'dont_merge_cookies': True})
encoding: 使用默认的 'utf-8' 就行。
dont_filter: indicates that this request should not be filtered by the scheduler.
This is used when you want to perform an identical request multiple times,
to ignore the duplicates filter. Use it with care, or you will get into crawling loops.
Default to False.
errback: 指定错误处理函数
不出意外的话,接下来就是 Response 的源码:
# 部分代码
class Response(object_ref):
def __init__(self, url, status=200, headers=None, body='', flags=None, request=None):
self.headers = Headers(headers or {})
self.status = int(status)
self._set_body(body)
self._set_url(url)
self.request = request
self.flags = [] if flags is None else list(flags)
def meta(self):
return self.request.meta
except AttributeError:
raise AttributeError("Response.meta not available, this response " \
"is not tied to any request")
参数跟上面的类似。
A Response object represents an HTTP response, which is usually
downloaded (by the Downloader) and fed to the Spiders for processing.
可以使用:
scrapy shell http://xxxx.xxx.xx
&&& dir(response)
在继续向下看:
# 第二个函数
def parse_item(self, response):
item = MyItem()
# populate `item` fields
# 相当于导航栏下面的列表页,此时可能还存在分页情况
# and extract item_details_url
yield scrapy.Request(item_details_url, self.parse_details, meta={'item': item})
接收到第一个函数得到并遍历的所有url的请求响应Response。并在当前页面中查找了所有的详细实体的初略信息,以及单品详细的url地址。
此时需要继续向下请求,请求详细的实体的页面。
在这个函数中使用到了 item,也可以不使用。直接将信息(比如实体根据导航标签的大体分类),通过Request的meta属性,传递给下一个callback处理函数。
继续向下看:
# 第三个函数
def parse_details(self, response):
item = response.meta['item']
# populate more `item` fields
return item
此时,请求已经得到了实体的具体页面,也就是实体详细页。(比如,根据博客的文章列表点击进入了文章)。
这时需要接收一下,从上一个函数中传递过来的信息。
def parse_details(self, response):
item = response.meta['item']
# 也可以使用如下方式,设置一个默认值
item = response.meta.get('item', None)
# 当 'item' key 不存在 meta字典中时,返回None
然后在在本页中使用 xpath,css,re等来选择详细的字段,至于具体的选择,以后再说吧~~~本来想简单的写点,然后就这么多了 ... ...
最后将最终得到的 item 返回即可。这样就能在
ITEM_PIPELINES 中得到数据,并进行下一步的处理了~~~
Copyright (C) , All Rights Reserved.
版权所有 闽ICP备号
processed in 0.035 (s). 12 q(s)

我要回帖

更多关于 scrapy start request 的文章

 

随机推荐