Scrapy框架
scrapy框架学习进阶:
这里接scrapy框架(1)的内容,
1、使用Request将新的请求加入请求队列;
2、使用pipline和item对返回页面信息持久化;
3、Scrapy的url去重源码;
4、cookie的使用;
4Request递归访问
使用Request,进行递归遍历:
from scrapy.http importRequest
#将新的url加入调度器,然后递归遍历解析
yield Request(url=new_url,callback=self.parse)
在setting.py文件中可以设置递归查找层数:
DEPTH_LIMIT = 1
5Pipline和item持久化
使用pipline将title和url持久化
在items.py增加对应持久化对象
示例:
#保存抽屉网新闻title和href
classChoutiItem(scrapy.Item):
title =scrapy.Field()
href =scrapy.Field()
在chouti.py导入对应Item
from ..items importChoutiItem
#创建item
choutiItem = ChoutiItem(title = a_detail,href =a_href)
#返回item
yield choutiItem
在pipelines.py加入查看item,这里也可以将item写入文件,
open_spider方法,spider打开时调用;
close_spider方法,spider关闭时调用;
from_crawler方法新建类对象,获取settings的配置内容,可以用来获取数据库信息,然后在__init__方法中初始化连接。
classProScrapyPipeline(object):
#初始化方法
def __init__(self):
pass
#返回类对象
@classmethod
deffrom_crawler(cls,crawler):
#将settings.py文件封装到settings参数
val = crawler.settings.get("DUPEFILTER_CLASS")
print(val)
returncls()
#爬虫打开时调用
defopen_spider(self,spider):
self.f = open("news.txt", 'a', encoding='utf-8')
print("pipline open")
#爬虫关闭时调用
defclose_spider(self,spider):
self.f.close()
print("pipline close")
defprocess_item(self, item, spider):
#查看spider,item
file = item["title"] + '\n' + item['href'] + '\n'
print(file)
#将信息写入文件
self.f.write(file)
#其他pipline继续处理item
return item
修改settings.py,让pipeline生效,取消注释:
可以加入多个Pipline做不同处理,300表示优先级,越小优先级越高。
ITEM_PIPELINES ={
'Pro_scrapy.pipelines.ProScrapyPipeline': 300,
}
如果process_item方法return item,那么所有Pipline根据优先级依次处理该item,不想该item处理需要raise dropitem。
from scrapy.exceptions importDropItem
#如果不想其他pipline处理这个item
raise DropItem
6URL访问去重
使用set()集合去重,将url放入set集合。
使用md5加密url,以固定长度存入数据库,使用set()可以将重复url去重。
示例:
#保存url,使用set,去重
urls_set =set()
#md5加密url
md5_url =self.md5(a_href)
if md5_url not inself.urls_set:
self.urls_set.add(md5_url)
print(a_detail,a_href)
defmd5(self,url):
importhashlib
obj =hashlib.md5;
obj.update(bytes(url,encoding='utf-8'))
return obj.hexdigest()
Scrapy自带有url去重功能,使用类RFPDupeFilter实现去重。
示例:
#获取返回网页所有a标签,标签列表
a_list = Selector(response=response).xpath('//a/@href')
for url ina_list:
#递归遍历所有url,dont_filter调用scrapy提供的url去重
yield Request(url=url,callback=self.parse,dont_filter=True)
scrapy的去重源码:
from scrapy.dupefilters importRFPDupeFilter
classRFPDupeFilter(BaseDupeFilter):
"""Request Fingerprint duplicates filter"""
def __init__(self, path=None, debug=False):
self.file =None
self.fingerprints =set()
self.logdupes =True
self.debug =debug
self.logger = logging.getLogger(__name__)
ifpath:
self.file = open(os.path.join(path, 'requests.seen'), 'a+')
self.file.seek(0)
self.fingerprints.update(x.rstrip() for x inself.file)
@classmethod
deffrom_settings(cls, settings):
debug = settings.getbool('DUPEFILTER_DEBUG')
returncls(job_dir(settings), debug)
defrequest_seen(self, request):
fp =self.request_fingerprint(request)
if fp inself.fingerprints:
returnTrue
self.fingerprints.add(fp)
ifself.file:
self.file.write(fp +os.linesep)
defrequest_fingerprint(self, request):
returnrequest_fingerprint(request)
defclose(self, reason):
ifself.file:
self.file.close()
deflog(self, request, spider):
ifself.debug:
msg = "Filtered duplicate request: %(request)s (referer: %(referer)s)"args = {'request': request, 'referer': referer_str(request) }
self.logger.debug(msg, args, extra={'spider': spider})
elifself.logdupes:
msg = ("Filtered duplicate request: %(request)s"
"- no more duplicates will be shown"
"(see DUPEFILTER_DEBUG to show all duplicates)")
self.logger.debug(msg, {'request': request}, extra={'spider': spider})
self.logdupes =False
spider.crawler.stats.inc_value('dupefilter/filtered', spider=spider)
我们可以自定义去重类,类似于RFPDupeFilter
#自定义UR'L去重类
classDuplicationFilter(object):
def __init__(self):
#创建set集合
self.urlset =set()
@classmethod
deffrom_settings(cls, settings):
returncls()
defrequest_seen(self, request):
if request.url inself.urlset:
returnTrue
#将url加入set
self.urlset.add(request.url)
print(self.urlset)
returnFalse
def open(self): #can return deferred
print("open")
defclose(self, reason):
print("close")
deflog(self, request, spider):
pass
在settings.py配置我们的自定义类
示例:
#配置url去重类
DUPEFILTER_CLASS = 'Pro_scrapy.duplicationfilter.DuplicationFilter'
7登陆cookies
使用cookies,需要导入相应包,创建对象保存cookie。
示例:
导入相应包:
fromscrapy.http.cookies importCookieJar
修改chouti.py,def parse()方法中编写代码:
#创建cookiejar对象,保存cookie容器
cookie_obj =CookieJar()
#获取当前请求的cookie,保存到cookieJar对象
cookie_obj.extract_cookies(response,response.request)
#拿到cookie
print(cookie_obj._cookies)
#带上用户名密码登陆,发送请求
yieldRequest(
url="https://dig.chouti.com/login",
method="POST",
body="phone=+861832573226&password=11223&loginType=2",
headers="{'Content-Type':' application/x-www-form-urlencoded; charset=UTF-8'}",
cookies=cookie_obj._cookies,
callback=self.loginSuc
)
defloginSuc(self,response):
print(response)
#登陆成功访问其他页面