python学习:python爬虫之Scrapy框架(2):请求队列,页面持久化,url去重,Cookie

Scrapy框架

  scrapy框架学习进阶:

  这里接scrapy框架(1)的内容,

  1、使用Request将新的请求加入请求队列;

  2、使用pipline和item对返回页面信息持久化;

  3、Scrapy的url去重源码;

  4、cookie的使用;

4Request递归访问

使用Request,进行递归遍历:

from scrapy.http import Request

#将新的url加入调度器,然后递归遍历解析

yield Request(url=new_url,callback=self.parse)

在setting.py文件中可以设置递归查找层数:

DEPTH_LIMIT = 1

 

5Pipline和item持久化

使用pipline将title和url持久化

在items.py增加对应持久化对象

示例:

#保存抽屉网新闻title和href

class ChoutiItem(scrapy.Item):

    title = scrapy.Field()

    href = scrapy.Field()

 

在chouti.py导入对应Item

from ..items import ChoutiItem

 

#创建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__方法中初始化连接。
class ProScrapyPipeline(object):

  #初始化方法

  def __init__(self):

      pass

#返回类对象 @classmethod def from_crawler(cls,crawler): #将settings.py文件封装到settings参数 val = crawler.settings.get("DUPEFILTER_CLASS") print(val) return cls() #爬虫打开时调用 def open_spider(self,spider): self.f = open("news.txt", 'a', encoding='utf-8') print("pipline open") #爬虫关闭时调用 def close_spider(self,spider): self.f.close() print("pipline close") def process_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 import DropItem

#如果不想其他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 in self.urls_set:

    self.urls_set.add(md5_url)

print(a_detail,a_href)


def md5(self,url):

    import hashlib

    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 in a_list:

    #递归遍历所有url,dont_filter调用scrapy提供的url去重

    yield Request(url=url,callback=self.parse,dont_filter=True)

scrapy的去重源码:

from scrapy.dupefilters import RFPDupeFilter

class RFPDupeFilter(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__)

        if path:

            self.file = open(os.path.join(path, 'requests.seen'), 'a+')

            self.file.seek(0)

            self.fingerprints.update(x.rstrip() for x in self.file)

 
    @classmethod

    def from_settings(cls, settings):

        debug = settings.getbool('DUPEFILTER_DEBUG')

        return cls(job_dir(settings), debug)

 
    def request_seen(self, request):

        fp = self.request_fingerprint(request)

        if fp in self.fingerprints:

            return True

        self.fingerprints.add(fp)

        if self.file:

            self.file.write(fp + os.linesep)

 
    def request_fingerprint(self, request):

        return request_fingerprint(request)

 
    def close(self, reason):

        if self.file:

            self.file.close()

    def log(self, request, spider):

        if self.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})

        elif self.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去重类

class DuplicationFilter(object):

 

    def __init__(self):

        #创建set集合

        self.urlset = set()

 

    @classmethod

    def from_settings(cls, settings):

        return cls()

 

    def request_seen(self, request):

        if  request.url in self.urlset:

            return True

        #将url加入set

        self.urlset.add(request.url)

        print(self.urlset)

        return False

 

    def open(self):  # can return deferred

        print("open")

 

    def close(self, reason):

        print("close")

 

    def log(self, request, spider):

        pass

 

在settings.py配置我们的自定义类

示例:

#配置url去重类

DUPEFILTER_CLASS = 'Pro_scrapy.duplicationfilter.DuplicationFilter'

 

7登陆cookies

    使用cookies,需要导入相应包,创建对象保存cookie。

示例:

导入相应包:

    from scrapy.http.cookies import  CookieJar

修改chouti.py,def parse()方法中编写代码:

 #创建cookiejar对象,保存cookie容器

    cookie_obj = CookieJar()

    #获取当前请求的cookie,保存到cookieJar对象

    cookie_obj.extract_cookies(response,response.request)

    #拿到cookie

    print(cookie_obj._cookies)

    #带上用户名密码登陆,发送请求

    yield Request(

        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

    )

def loginSuc(self,response):

    print(response)

    #登陆成功访问其他页面

 

posted @ 2021-01-07 20:38  渔歌晚唱  阅读(328)  评论(0)    收藏  举报