首页 > 其他 > 详细

Scrapy爬虫框架学习

时间:2019-04-06 12:09:16      阅读:110      评论:0      收藏:0      [点我收藏+]

一、Scrapy框架简介

1. 下载页面
2. 解析
3. 并发
4. 深度

 

二、安装

linux下安装    
    pip3 install scrapy
    
windows下安装
    a.pip3 install wheel
    b.下载twisted和pywin32 http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
    c.进入下载目录
         执行pip3 install Twisted-18.7.0-cp36-cp36m-win_amd64.whl     #cp36为适合python3.6
         执行pip3 install  pywin32-224-cp36-cp36m-win_amd64.whl
  d.pip3 install scrapy
    e.下载并安装pywin32:https://sourceforge.net/projects/pywin32/files/  #找到适合本机python版本的64位

 

 

三、Scrapy整体架构图

  3.1 Scrapy使用Twisted异步网络库来处理网络通讯

技术分享图片

 

  3.2 各个主要文件说明

  spiders(蜘蛛)文件夹:如ip138.com

name    #不能省略,最好不要修改
starts_urls  #起始url
allowed_domains    #爬取允许域名列表,起始url不受影响。网页中的外链受此限制

 

 

 

四、基本使用

1. 指定初始url
2. 解析器响应内容
    - 给调度器
    - 给item:pipeline;用于做格式化;持久化

基本步骤:
a:scrapy startproject 项目名   #创建项目
b:进入项目目录
c:scrapy genspider baidu www.baidu.com  #创建start_url
d:打开项目名\spiders\baidu.py进行编辑
e:scrapy crawl baidu    #执行,加--nolog可以不显示日志,如果没有内容显示,可能此IP已经有防爬机制,可换个不知名ip试试

 

五、筛选器

  5.1  Selector介绍

  在scrapy中,可以使用Selector筛选器,代替BeautifulSoup

  在scrapy项目里的spiders文件里的baidu.py爬虫文件编辑,导入Selecotr模块

from scrapy.selector import Selector

 

  5.2 Selector(response=response).xpath()基本用法

//        #表示子子孙孙,即所有
.//        #当前对象的子孙中
/            #儿子
/div        #儿子中的div标签
//div[@id]  #所有标签含有id的div标签
/div[@id=i1]    #儿子中的div且id =‘i1‘的标签
obj.extract()        #列表中每一个对象转换成字符串 ==>返回的是列表
obj.extract_first()  #列表中每一各对象转换成字符串==>返回的是列表中第一个元素
//div/text()        #获取所有div标签里的文本==》返回的是列表,元素是对象
//a/@href           #获取所有a标签里的url==》返回的是列表,元素是对象
//a[starts-with(@href,"link")]    #获取所有a标签,并且href属性是以link开头的
//a[re:test(@href,"/sitehome/p/\d+")]/@href   #正则,获取所有a标签属性href符合/sitehome/p/数字的
//div[@id=i1][@href=‘‘xx]   #[][]且的意思,即所有含有id=‘i1‘且href=‘xxx‘的div标签
//a[contains(@href, "link")]    #所有href字段包含link字符串的a标签

 

 

  5.3 简单示例

  需求:在www.ip138.com网站里,打印如下a标签的文本内容和url地址

技术分享图片

 

  在爬虫文件(baidu.py)里的parse类方法里编辑 

技术分享图片
# -*- coding: utf-8 -*-
import scrapy
from scrapy.selector import Selector

class BaiduSpider(scrapy.Spider):
    name = baidu
    allowed_domains = [ip138.com]
    start_urls = [http://www.ip138.com/]

    def parse(self, response):
        #请求该页面下所有a标签==》列表,每个元素都是对象
        #找到div标签里有class=mod-guide属性下的所有子孙a标签里文本内容
        text_obj_list = Selector(response=response).xpath(//div[@class="module mod-guide"]//a/text())

        # 找到div标签里有class=mod-guide属性下的所有子孙a标签里url
        url_obj_list = Selector(response=response).xpath(//div[@class="module mod-guide"]//a/@href)

        #将列表中对象转化成列表中字符串
        text_str_list = text_obj_list.extract()
        url_str_list = url_obj_list.extract()

        for a_text,a_url in zip(text_str_list,url_str_list):
            print(a_text,a_url)
代码

 

  如何运行代码?

在cmd窗口,进入项目目录,运行scrapy  crawl  baidu

 

  5.4 获取当前网页中的所有页码实例

  需求:获取博客园里的首页页码url

技术分享图片

 

  

  在爬虫文件(ip138.py)里的parse类方法里编辑

技术分享图片
# -*- coding: utf-8 -*-
import scrapy
from scrapy.selector import Selector

class Ip138Spider(scrapy.Spider):
    name = ip138
    allowed_domains = [www.cnblogs.com]
    start_urls = [https://www.cnblogs.com/]

    urls_set = set()

    def parse(self, response):
        # text_obj_list = Selector(response=response).xpath(‘//div[@class="module mod-guide"]//a/text()‘)
        # url_obj_list = Selector(response=response).xpath(‘//div[@class="module mod-guide"]//a/@href‘)
        #
        # text_str_list = text_obj_list.extract()
        # url_str_list = url_obj_list.extract()
        #
        # for text,url in zip(text_str_list,url_str_list):
        #     print(text,url)

        #获取当前页里的所有页码的url对象列表
        url_obj_list = Selector(response=response).xpath(//div[@class="pager"]/a/@href)
        ##或者2: starts-with(@属性,‘值开头‘)
        #url_obj_list = Selector(response=response).xpath(‘//a[starts-with(@href,"/sitehome/p/")]/@href‘)
        ##或者3:正则表达式固定用法re:test(@属性值,"正则表达式")
        #url_obj_list = Selector(response=response).xpath(‘//a[re:test(@href,"/sitehome/p/\d+")]/@href‘)

        #将对象列表转换成字符串列表
        url_str_list = url_obj_list.extract()
        for url in url_str_list:
            print(url)

            #1.通过集合去除重复url
            #2.使用加密的MD5存储url,好处:加密和等长
            url_md5 = self.my_md5(url)
            if url_md5 not in self.urls_set:
                self.urls_set.add(url_md5)
                print(url_md5)
            else:
                print(%s已经存在%url_md5)

    def my_md5(self,url):
        import hashlib
        obj = hashlib.md5()
        obj.update(bytes(url,encoding=utf-8))
        return obj.hexdigest()
代码

 

  5.5 获得当前网页里的页码自动请求爬取实例

  需求:自动爬取博客园的所有页码(基于5.4案例的基础)

技术分享图片

  

  在爬虫文件(ip138.py)里的parse类方法里编辑

技术分享图片
# -*- coding: utf-8 -*-
import scrapy
from scrapy.selector import Selector
from scrapy.http import Request

class Ip138Spider(scrapy.Spider):
    name = ip138
    allowed_domains = [www.cnblogs.com]
    start_urls = [https://www.cnblogs.com/]

    urls_set = set()

    def parse(self, response):

        #获取当前页里的所有页码的url对象列表
        url_obj_list = Selector(response=response).xpath(//div[@class="pager"]/a/@href)
        ##或者2: starts-with(@属性,‘值开头‘)
        #url_obj_list = Selector(response=response).xpath(‘//a[starts-with(@href,"/sitehome/p/")]/@href‘)
        ##或者3:正则表达式固定用法re:test(@属性值,"正则表达式")
        #url_obj_list = Selector(response=response).xpath(‘//a[re:test(@href,"/sitehome/p/\d+")]/@href‘)

        #将对象列表转换成字符串列表
        url_str_list = url_obj_list.extract()
        for url in url_str_list:

            #1.通过集合去除重复url
            if url not in self.urls_set:
                #print(url)
                self.urls_set.add(url)
                #拼接完整的url地址
                full_url = self.start_urls[0] + url
                #将url页码传给调度器去请求,并将下载的结果交给parse方法,yield的作用是将请求放入调度器
                yield Request(url=full_url,callback=self.parse)

            for url in self.urls_set:
                print(url)
代码

 

  在setting.py中结尾新增一行DEPTH_LIMIT=1来指定递归的层次,默认是0,所有层次

   实例中关键点概括

@href    #取属性值
starts-with(@href,"xx")   #属性href的值以xx开始
re:test(@href,"/sitehome/p/\d+")   #正则re:test固定搭配
yield Request(url=full_url,callback=self.parse)   #交给调度器

 

六、item,pipeline使用

  6.1 需求:将博客园的文章标题和url保存到一个文件a.txt文件里。

     各文件代码如下:

技术分享图片
# -*- coding: utf-8 -*-
import scrapy
from scrapy.selector import Selector
from scrapy.http import Request
from .. import items

class Ip138Spider(scrapy.Spider):
    name = ip138
    allowed_domains = [www.cnblogs.com]
    start_urls = [https://www.cnblogs.com/]

    urls_set = set()

    def parse(self, response):

        #获取当前页面里的标题和url==>返回字符串
        title_str_list = Selector(response=response).xpath(//a[@class="titlelnk"]/text()).extract()
        href_str_list = Selector(response=response).xpath(//a[@class="titlelnk"]/@href).extract()

        for title_str,href_str in zip(title_str_list,href_str_list):
            #print(title_str,‘   ‘,href_str)
            
            #此处的参数title,和href来自于items.py文件里类Cnblogs里的属性
            item_obj = items.Cnblogs(title=title_str,href=href_str)

            #将item对象传递给pipelines
            yield item_obj



        #获取当前页里的所有页码的url对象列表
        page_obj_list = Selector(response=response).xpath(//div[@class="pager"]/a/@href)
        ##或者2: starts-with(@属性,‘值开头‘)
        #page_obj_list = Selector(response=response).xpath(‘//a[starts-with(@href,"/sitehome/p/")]/@href‘)
        ##或者3:正则表达式固定用法re:test(@属性值,"正则表达式")
        #page_obj_list = Selector(response=response).xpath(‘//a[re:test(@href,"/sitehome/p/\d+")]/@href‘)

        #将对象列表转换成字符串列表
        page_str_list = page_obj_list.extract()
        for url in page_str_list:

            #1.通过集合去除重复url
            if url not in self.urls_set:
                self.urls_set.add(url)
                print(url)

                #拼接完整的url地址
                full_url = self.start_urls[0] + url
                #将url页码传给调度器去请求,并将下载的结果交给parse方法,yield的作用是将请求放入调度器
                yield Request(url=full_url,callback=self.parse)
ip138.py文件
技术分享图片
# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class Cnblogs(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field()
    href = scrapy.Field()
items.py文件
技术分享图片
# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don‘t forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html


class Day0310Pipeline(object):
    def process_item(self, item, spider):
        content = "%s    %s\n"%(item[title],item[href])
        f = open(a.json,a)
        f.write(content)
        f.close()
        # return item
pipelines.py文件
技术分享图片
ITEM_PIPELINES = {
   day0310.pipelines.Day0310Pipeline: 300,
}
setting.py文件

 

  6.2 实例中关键点概括

#items.py文件中
class Cnblogs(scrapy.Item):     
    title = scrapy.Field()
    href = scrapy.Field()

#ip138.py文件中
from .. import items
item_obj = items.Cnblogs(title=title_str,href=href_str)   #此处的参数title,和href来自于items.py文件里类Cnblogs里的属性

yield item_obj        #将item对象传递给pipelines

#pipelines.py文件中,可对收集到的数据进行存储
class Day0310Pipeline(object):
    def process_item(self, item, spider):   #item为ip138.py文件里的对象化的数据,spider为来自哪只蜘蛛对象
        content = "%s    %s\n"%(item[title],item[href])
        f = open(a.json,a)
        f.write(content)
        f.close()

#setting.py文件中注册下pipelines的类
ITEM_PIPELINES = {
   day0310.pipelines.Day0310Pipeline: 300,
}
数字越高越优先

 

Scrapy爬虫框架学习

原文:https://www.cnblogs.com/lisenlin/p/9321145.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!