• 爬虫scrapy


    爬虫scrapy

    点击这里还可以去我的博客主页o
    点击这里还可以去大神的学习笔记o

    前言

    本页只是为了方便本人以后复习爬虫scrapy用的笔记markdown

    纯属娱乐,如有雷同,打死不认——


    1. 开启scrapy之旅
    2. 常用的工具命令
    3. 项目开始以及连接mongodb
    4. scrapy选择器xpath和css选择器
    5. scrapy框架实现篇
    6. scrapy避免被禁止
    7. 自动爬取网页实战
    8. crawlspider快速抓取

    开启scrapy之旅

    1.安装好虚拟环境virtualenv scrapy_env
    进入scripts然后activate进入虚拟
    2.下载相应的包
    分别是顺序pip intsall
    wheel,lxml,PyOpenssl,Twisted,Pywin32,Scrapy
    3.开始scrapy项目 scrapy startproject quote
    4.然后scrapy genspider quotes quotes.toscrape.com
    打开pycharm打开相应文件夹,里面就是这个项目quote,里面有同名quote然后里面spiders还有自己创建的quotes

    遇到的问题
    因为创建了quote再pychram里面打开终端就直接打开了quote一个虚拟环境,然后执行scrapy怎样都是'scrapy' 不是内部或外部命令,也不是可运行的程序
    百度半天说没有加入path,然后我吧D:Python_codescrapy_envScripts加入环境了后发现进入quote这个虚拟也不行,'scrapy' 不是内部或外部命令,也不是可运行的程序,然后我想起来,这个是虚拟环境,加入path也不能进入这个虚拟,所以我退出虚拟quote,deactivate进入scrapy_env的虚拟即scrapy的安装虚拟路径和环境再执行,ok了
    点击这里还可以去scrapy官方文档
    点击这里去教程scrapy菜鸟教程


    常用的工具命令

    scrapy 中常用的工具分两种1是全局命令,2是项目命令
    全局命令就是不依靠Scrapy就能直接运行,而项目命令就是需要在项目中才能运行
    1全局命令 我们可以通过scrapy -h直接查看所有的全局命令
    2项目命令基于项目使用,进入项目才能使用


    解析quote scrapy

    第一是进入scrapy_env的虚拟,因为我的scrapy和一系列的包都在这个虚拟下载的,不是在全局下载的,当时pip的时候就在虚拟pip,这样呢以后每个项目都能用scrapy的包啊虚拟这些,麻烦的就是每次需要在终端进入这个虚拟才行
    
    首先在item中定义好数据
    class QuoteItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        text=scrapy.Field()
        author=scrapy.Field()
        tags=scrapy.Field()
    然后在spiders目录下的quotes中
        def parse(self, response):
            quotes=response.css('.quote')#.quote是pyquery的特点
            for quote in quotes.css('.text::text').extract_frist():
               item=QuoteItem()
                text=quote.css('.text::text').extract_frist()
                author=quote.css('.author::text').extract_frist()
                tags=quote.css('.tags .tag::text').extract()  #所有结果,多个内容,类似于findall
                item['text'] = text
                item['author']=author
                item['tags']=tags
                yield item
            next =response.css('.pager .next a::attr(href)').extract_first()  #这个是参看f12里面下一页按钮那里的的 是两个class
            url=response.urljoin(next) #urljoin是一个方法,可以生成一个完整的url因为是不完整的比如少http://等
            yield scrapy.Request(url=url,callback=self.parse)  #递归,自己回调自己
    
    解释下.quote .text这是一种css的选择方式而::text则是scrapy的方式,表示输出data的字符串,而直接用.css的话输出为标签,
    extract表示输出返回的是一个列表,_frist则就是输出第一个标签没有frist就算全部
    然后在终端,如果在Shell因为我一开始写了命令crapy shell quotes.toscrapy.com进入了这个交互环境中,所以执行exit()先退到scrapy_env的虚拟当中再执行scrapy crawl quotes(quotes是那个文件夹名)就 ok了
    如果最后执行 scrapy crawl quotes没问题后要想保存数据可以scrapy crawl quotes -0 quotes.json就保存为json格式了同样的其他格式也是这样比如scrapy crawl quotes -0 quotes.csv等就会发现有这个文件了,里面数据也在里面格式也更加清楚
    在pipeline里面
    from scrapy.exceptions import DropItem
    import pymongo
    
    class TextPipeline(object):
        def __init__(self):
            self.limit=50
        def process_item(self, item, spider):
            if item['text']:
                if len (item['text'])>self.limit:
                    item['text']=item['text'][0:self.limit].rstrip()+'........' #rstrip去除空格
                    return item
                else:
                    return DropItem('miss Text')
    
    class mongopipeline(object):
        def __init__(self,mongo_url,mongo_db):
            self.mongo_url=mongo_url
            self.mongo_db=mongo_db
    
        @classmethod
        def from_crawler(cls,crawler):
            return cls(
                mongo_url=crawler.setting.get('MONGO_URL'),
                mongo_db=crawler.setting.get('MONGO_DB'),
            )
        def open_spider(self,spider):
            self.client=pymongo.MongoClient(self.mongo_url)
            self.db=self.client(self.mongo_db)
    
        def process_item(self,item,spider):
            name=item.__class__.__name__
            self.db[name].insert(dict(item))
            return item
    
        def close_spider(self,spider):
            self.client.close()
    而我的电脑连接mongodb两种方法 ,第一种直接用命令mongod--dbpath E:data或者直接搜索服务找到mondodb server 打开即可
    而且在MongoDB中经常我错的地方就是
    修改完成后的代码:
    client = pymongo.MongoClient('localhost')
    db = client['my_database']#注意这里用中括号!!
    不然总会'MongoClient' object is not callable
    

    xpath和css选择器

    
    
    我们将在下面的例子中使用这个 XML 文档。
    
    <?xml version="1.0" encoding="ISO-8859-1"?>
    
    <bookstore>
    
    <book>
      <title lang="eng">Harry Potter</title>
      <price>29.99</price>
    </book>
    
    <book>
      <title lang="eng">Learning XML</title>
      <price>39.95</price>
    </book>
    
    </bookstore>
    选取节点
    XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。
    
    下面列出了最有用的路径表达式:
    表达式	描述
    nodename	选取此节点的所有子节点。
    /	从根节点选取。
    //	从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
    .	选取当前节点。
    ..	选取当前节点的父节点。
    @	选取属性。
    实例
    在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:
    
    路径表达式	结果
    bookstore	选取 bookstore 元素的所有子节点。
    /bookstore	
    选取根元素 bookstore。
    
    注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
    
    bookstore/book	选取属于 bookstore 的子元素的所有 book 元素。
    //book	选取所有 book 子元素,而不管它们在文档中的位置。
    bookstore//book	选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
    //@lang	选取名为 lang 的所有属性。
    谓语(Predicates)
    谓语用来查找某个特定的节点或者包含某个指定的值的节点。
    
    谓语被嵌在方括号中。
    
    实例
    在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:
    
    路径表达式	结果
    /bookstore/book[1]	选取属于 bookstore 子元素的第一个 book 元素。
    /bookstore/book[last()]	选取属于 bookstore 子元素的最后一个 book 元素。
    /bookstore/book[last()-1]	选取属于 bookstore 子元素的倒数第二个 book 元素。
    /bookstore/book[position()<3]	选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
    
    //title[@lang]	选取所有拥有名为 lang 的属性的 title 元素。
    //title[@lang='eng']	选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
    /bookstore/book[price>35.00]	选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
    /bookstore/book[price>35.00]/title	选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。
    选取未知节点
    XPath 通配符可用来选取未知的 XML 元素。
    /html/body/h2/text() 即 提取出h2便签的内容
    使用//可以提取某个标签的所有信息
    //p 选取所有p标签的所有信息
    加入很多段 <img src='......' class='f1'>
    这时
    //img[@class='f1']就是获取所有class属性值为f1的<img>标签的内容
    通配符	描述
    *	匹配任何元素节点。
    @*	匹配任何属性节点。
    node()	匹配任何类型的节点。
    实例
    在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
    
    路径表达式	结果
    /bookstore/*	选取 bookstore 元素的所有子元素。
    //*	选取文档中的所有元素。
    //title[@*]	选取所有带有属性的 title 元素。
    选取若干路径
    通过在路径表达式中使用“|”运算符,您可以选取若干个路径。
    
    实例
    在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
    
    路径表达式	结果
    //book/title | //book/price	选取 book 元素的所有 title 和 price 元素。
    //title | //price	选取文档中的所有 title 和 price 元素。
    /bookstore/book/title | //price	选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。
    
    scrapy中的css选择器语法
    *
    所有节点
    #container
    选择id为container的节点
    .container
    选择class为container的节点
    li a
    选择所有li下的所有a节点
    ul + p
    选择ul后的第一个p节点
    div#container > ul
    选择id为container的div的第一个ul子节点
    ul ~ p
    选取与ul相邻的所有的p元素
    a[title]
    选取所有包含有title属性的a元素
    a[href="http://jobbole.com"]
    选取所有href属性为jobbole.com的a元素
    a[href*="jobbole"]
    选取所有href属性包含jobbole的a元素
    a[href^="http"]
    选取所有href属性以http开头的a元素
    a[href$=".jpt"]
    选取所有href属性以.jpg结尾的a元素
    input[type=radio]:checked
    选取选中的radio元素
    div:not(#container)
    选取所有id不为container的div元素
    li:nth-child(3)
    选取第三个li元素
    tr:nth-child(2n)
    第偶数个tr
    
    
    scrapy选择器实战
    
    Scrapy选择器构建于 lxml 库之上,这意味着它们在速度和解析准确性上非常相似。
    我们将使用 Scrapy shell
    (提供交互测试)和位于Scrapy文档服务器的一个样例页面,来解释如何使用选择器:
    http://doc.scrapy.org/en/latest/_static/selectors-sample1.html
    
    
    这里是它的HTML源码:
    <html>
     <head>
      <base href='http://example.com/' />
      <title>Example website</title>
     </head>
     <body>
      <div id='images'>
       <a href='image1.html'>Name: My image 1 <br />![](image1_thumb.jpg)</a>
       <a href='image2.html'>Name: My image 2 <br />![](image2_thumb.jpg)</a>
       <a href='image3.html'>Name: My image 3 <br />![](image3_thumb.jpg)</a>
       <a href='image4.html'>Name: My image 4 <br />![](image4_thumb.jpg)</a>
       <a href='image5.html'>Name: My image 5 <br />![](image5_thumb.jpg)</a>
      </div>
     </body>
    </html>
    
    3.1 构造选择器
    首先, 我们打开shell:
    scrapy shell http://doc.scrapy.org/en/latest/_static/selectors-sample1.html
    
    
    接着,当shell载入后,您将获得名为response
    的shell变量,其为响应的response, 并且在其 response.selector属性上绑定了一个 selector。
    因为我们处理的是HTML,选择器将自动使用HTML语法分析。
    那么,通过查看 HTML code 该页面的源码,我们构建一个XPath来选择title标签内的文字:
    
    >>> response.selector.xpath('//title/text()')
    [<Selector (text) xpath=//title/text()>]
    
    
    由于在response中使用XPath、CSS查询十分普遍,因此,Scrapy提供了两个实用的快捷方式: response.xpath() 及 response.css():
    
    >>> response.xpath('//title/text()')
    [<Selector (text) xpath=//title/text()>]
    >>> response.css('title::text')
    [<Selector (text) xpath=//title/text()>]
    
    
    如你所见, .xpath()及 .css()方法返回一个类 SelectorList 的实例, 它是一个新选择器的列表。这个API可以用来快速的提取嵌套数据。
    为了提取真实的原文数据,你需要调用 .extract()方法如下:
    
    >>> response.xpath('//title/text()').extract()
    [u'Example website']
    
    
    如果想要提取到第一个匹配到的元素, 必须调用 .extract_first()  selector:
    
    >>> response.xpath('//div[@id="images"]/a/text()').extract_first()
    u'Name: My image 1 '
    
    
    现在我们将得到根URL(base URL)和一些图片链接:
    
    >>> response.xpath('//base/@href').extract()
    [u'http://example.com/']
    
    >>> response.css('base::attr(href)').extract()
    [u'http://example.com/']
    
    >>> response.xpath('//a[contains(@href, "image")]/@href').extract()
    [u'image1.html',
     u'image2.html',
     u'image3.html',
     u'image4.html',
     u'image5.html']
    
    >>> response.css('a[href*=image]::attr(href)').extract()
    [u'image1.html',
     u'image2.html',
     u'image3.html',
     u'image4.html',
     u'image5.html']
    
    >>> response.xpath('//a[contains(@href, "image")]/img/@src').extract()
    [u'image1_thumb.jpg',
     u'image2_thumb.jpg',
     u'image3_thumb.jpg',
     u'image4_thumb.jpg',
     u'image5_thumb.jpg']
    
    >>> response.css('a[href*=image] img::attr(src)').extract()
    [u'image1_thumb.jpg',
     u'image2_thumb.jpg',
     u'image3_thumb.jpg',
     u'image4_thumb.jpg',
     u'image5_thumb.jpg']
    
    3.2选择器嵌套
    
    选择器方法( .xpath() or .css() )返回相同类型的选择器列表,因此你也可以对这些选择器调用选择器方法。下面是一个例子:
    
    >>> links = response.xpath('//a[contains(@href, "image")]')
    >>> links.extract()
    [u'<a href="image1.html">Name: My image 1 <br>![](image1_thumb.jpg)</a>',
     u'<a href="image2.html">Name: My image 2 <br>![](image2_thumb.jpg)</a>',
     u'<a href="image3.html">Name: My image 3 <br>![](image3_thumb.jpg)</a>',
     u'<a href="image4.html">Name: My image 4 <br>![](image4_thumb.jpg)</a>',
     u'<a href="image5.html">Name: My image 5 <br>![](image5_thumb.jpg)</a>']
    
    >>> for index, link in enumerate(links):
            args = (index, link.xpath('@href').extract(), link.xpath('img/@src').extract())
            print 'Link number %d points to url %s and image %s' % args
    
    Link number 0 points to url [u'image1.html'] and image [u'image1_thumb.jpg']
    Link number 1 points to url [u'image2.html'] and image [u'image2_thumb.jpg']
    Link number 2 points to url [u'image3.html'] and image [u'image3_thumb.jpg']
    Link number 3 points to url [u'image4.html'] and image [u'image4_thumb.jpg']
    Link number 4 points to url [u'image5.html'] and image [u'image5_thumb.jpg']
    
    3.3 结合正则表达式使用选择器(selectors)
    
    Selector 也有一个 .re()方法,用来通过正则表达式来提取数据。然而,不同于使用 .xpath() 或者 .css() 方法, .re() 方法返回unicode字符串的列表。所以你无法构造嵌套式的 .re() 调用。
    下面是一个例子,从上面的 HTML code 中提取图像名字:
    
    >>> response.xpath('//a[contains(@href, "image")]/text()').re(r'Name:s*(.*)')
    [u'My image 1',
     u'My image 2',
     u'My image 3',
     u'My image 4',
     u'My image 5']
    
    
    另外还有一个糅合了 .extract_first() 与 .re() 的函数 .re_first() . 使用该函数可以提取第一个匹配到的字符串:
    
    >>> response.xpath('//a[contains(@href, "image")]/text()').re_first(r'Name:s*(.*)')
    u'My image 1'
    
    

    scrapy框架实现篇

    创建一个项目scrapy startproject name
    Items实战

    进入items 其实items就是容器,保存爬取的数据,储蓄作用
    创建的items会加上你项目的名称自动创建类
    如
    class HellScrapyItem(scrapy.Item):#继承scrapy下的Item类
        # define the fields for your item here like:
        # name = scrapy.Field()
        urlname=scrapy.Field()
        urlkey=scrapy.Field()
        urlcr=scrapy.Field()
        urladdr=scrapy.Field()
    这个类里面定义结构化数据,即将scrapy下的Field类实例化
    然后我们要用的时候实例化这个类就可以了
    如:weisuen=person(urlname='weiwei',urlkey='123',urlcr='sdda',urladdr='asd')
    然后print(weisuen)就有了
    

    parse方法
    默认的回调函数
    就是很多函数返回的时候有一个callback=
    就是这个


    Spider编写

    scrapy.spiders.Spider
    这是最简单的蜘蛛,也是每个其他蜘蛛必须继承的蜘蛛(包括与Scrapy捆绑在一起的蜘蛛,以及你自己编写的蜘蛛)。它不提供任何特殊功能。它只提供了一个默认start_requests()实现,它从start_urlsspider属性发送请求,并parse 为每个结果响应调用spider的方法。
    
    而我们可以通过项目中运行genspider命令创建一个爬虫文件
    scrapy genspider weisuen iqianyue.com
    然后就有一个weisuen.py在spiders文件下
    并且已经自动生成了下面代码
    class WeisuenSpider(scrapy.Spider):
        name = 'weisuen'
        allowed_domains = ['iqianyue.com']
        start_urls = ['http://iqianyue.com/']
    
        def parse(self, response):
            pass
    这个名为parse的方法是处理scrapy爬虫爬行到网页响应的默认方法,如果有特别指定的回调函数就不用这个,一般默认这个,由自己编写,
    同时该方法也负责链接的跟进
        def parse(self, response):
            item=HellScrapyItem()
            item['urlname']=response.xpath('/html/head/title/text()')
            print(item['urlname'])
            然后执行scrapy crawl weisuen就会打印出来开头的文字
            [<Selector xpath='/html/head/title/text()' data='千月枫痕_遇见更文艺的你_千月枫痕'>]
    就OK了
    除了parse,Scrapy的Spider中常见的属性和方法还有
    
    make_requests_from_url(url)
    该方法被start_requests()调用,实现生成Request请求对象,回调默认的是parse()函数,当然也可以回调指定函数如
    def make_requests_from_url(self,url):
        return scrapy.Request(url=url,callback=self.parse_index)
    def parse_index(self,response):
        print('Baidu',response.status)
    
    start_requests()
    该方法默认读取start_url属性中定义的网址,并为每个网址生成一个Request请求对象,并返回迭代对象,当然也可以不用start_url中的网址,也可以自定义
    如
    import scrapy
    from hell_scrapy.items import HellScrapyItem
    
    class WeisuenSpider(scrapy.Spider):
        name = 'weisuen'
        allowed_domains = ['iqianyue.com']
        start_urls = ['http://iqianyue.com/']
        urls2=(
            'http://www.jd.com',
            'http://sina.com.cn',
            'http://yum.iqianyue.com',
        )
        def start_requests(self):
            for url in self.urls2:
                yield self.make_requests_from_url(url)
                
                
        def parse(self, response):
            item=HellScrapyItem()
            item['urlname']=response.xpath('/html/head/title/text()')
            print(item['urlname'])
            这样的话我们的start_urls其实是没有作用的
            如输出答案为
            [<Selector xpath='/html/head/title/text()' data='京东(JD.COM)-正品低价、品质保障、配送及时、轻松购物!'>]
            [<Selector xpath='/html/head/title/text()' data='新浪首页'>]
            [<Selector xpath='/html/head/title/text()' data='韬云科技|国内首家企业专属云平台'>]
        
        还可以这样
        start_requests(self):
        yield scrapy.Request(url='http://www.baidu.com',callback=self.parse.index)
        指定url或者一个url列表函数
    
    
    __init__()
    该方法主要负责爬虫的初始化,为构造函数
    当然在传参时它的作用也无比明显
    
    allowed_domains是允许的域名,当有很多允许域名而又懒的添加时可以删去。
    这些都可以在上面的连接点开教程看
        现在让我们看看我们的蜘蛛被修改为递归地跟随到下一页的链接,从中提取数据:
    
    import scrapy
    
    
    class QuotesSpider(scrapy.Spider):
        name = "quotes"
        start_urls = [
            'http://quotes.toscrape.com/page/1/',
        ]
    
        def parse(self, response):
            for quote in response.css('div.quote'):
                yield {
                    'text': quote.css('span.text::text').get(),
                    'author': quote.css('small.author::text').get(),
                    'tags': quote.css('div.tags a.tag::text').getall(),
                }
    
            next_page = response.css('li.next a::attr(href)').get()
            if next_page is not None:
                next_page = response.urljoin(next_page)
                yield scrapy.Request(next_page, callback=self.parse)
                现在,在提取数据之后,该parse()方法查找到下一页的链接,使用该urljoin()方法构建完整的绝对URL (因为链接可以是相对的)并向下一页生成新请求,将自身注册为回调处理下一页的数据提取并保持爬网遍历所有页面。
    
    你在这里看到的是Scrapy跟踪链接的机制:当你在回调方法中产生一个Request时,Scrapy会安排发送该请求并注册一个回调方法,以便在该请求完成时执行。
    
    使用此功能,您可以根据您定义的规则构建跟踪链接的复杂爬网程序,并根据其访问的页面提取不同类型的数据。
    
    在我们的示例中,它创建了一种循环,跟随到下一页的所有链接,直到它找不到 - 用于爬行博客,论坛和其他具有分页的网站。
    创建请求的快捷方式
    作为创建Request对象的快捷方式,您可以使用 response.follow:
    
    import scrapy
    
    
    class QuotesSpider(scrapy.Spider):
        name = "quotes"
        start_urls = [
            'http://quotes.toscrape.com/page/1/',
        ]
    
        def parse(self, response):
            for quote in response.css('div.quote'):
                yield {
                    'text': quote.css('span.text::text').get(),
                    'author': quote.css('span small::text').get(),
                    'tags': quote.css('div.tags a.tag::text').getall(),
                }
    
            next_page = response.css('li.next a::attr(href)').get()
            if next_page is not None:
                yield response.follow(next_page, callback=self.parse)
    与scrapy.Request不同,它response.follow直接支持相对URL - 无需调用urljoin(urljoin是构造方法前面)。
    绝对URL,就是总是以域名(或者/)开头的网址就是"绝对URL"。
    注释:"/"代表域名对应的网站根目录。
    例如:http://www.baidu.com/image/baobao.gif。注意,response.follow只返回一个Request实例; 你仍然需要提出这个请求。
    
    您也可以传递选择器response.follow而不是字符串; 此选择器应提取必要的属性:
    
    for href in response.css('li.next a::attr(href)'):
        yield response.follow(href, callback=self.parse)
    对于<a>元素,有一个快捷方式:response.follow自动使用其href属性。所以代码可以进一步缩短:
    
    for a in response.css('li.next a'):
        yield response.follow(a, callback=self.parse)
    注意
    response.follow(response.css('li.next a'))无效
    是因为 response.css返回一个类似于列表的对象,其中包含所有结果的选择器,而不是单个选择器。甲for象在上面的例子中循环,或 是好的。response.follow(response.css('li.next a')[0])
    
    更多示例和模式
    import scrapy
    class AuthorSpider(scrapy.Spider):
        name = 'author'
        start_urls = ['http://quotes.toscrape.com/']
        def parse(self, response):
            # follow links to author pages
            for href in response.css('.author + a::attr(href)'):
                yield response.follow(href, self.parse_author)
    
            # follow pagination links
            for href in response.css('li.next a::attr(href)'):
                yield response.follow(href, self.parse)
    
        def parse_author(self, response):
            def extract_with_css(query):
                return response.css(query).get(default='').strip()
    
            yield {
                'name': extract_with_css('h3.author-title::text'),
                'birthdate': extract_with_css('.author-born-date::text'),
                'bio': extract_with_css('.author-description::text'),
            }
            这个蜘蛛将从主页面开始,它将跟随作者页面的所有链接,parse_author为每个页面调用回调,以及parse我们之前看到的与回调的分页链接。这里我们将回调传递给response.follow位置参数以使代码更短; 它也适用于scrapy.Request。
    该parse_author回调定义了一个辅助函数从CSS查询提取和清理数据,并产生了Python字典与作者的数据。
    这个蜘蛛演示的另一个有趣的事情是,即使同一作者有很多引用,我们也不必担心多次访问同一个作者页面。默认情况下,Scrapy会筛选出已访问过的URL的重复请求,从而避免因编程错误而导致服务器过多的问题。这可以通过设置进行配置 DUPEFILTER_CLASS
            这个简而言之就是
    开始 进入第一个for循环一直将页面里的作者信息链接提取出来,通过follow方法生成Request再回调parser_author函数这样一直到这一页的作者链接完毕,然后下一个for循环 即下一页。
    就如前面所言。当你在回调方法中产生一个Request时,Scrapy会安排发送该请求并注册一个回调方法,以便在该请求完成时执行。
    传参
    import scrapy
    
    
    class QuotesSpider(scrapy.Spider):
        name = "quotes"
    
        def start_requests(self):
            url = 'http://quotes.toscrape.com/'
            tag = getattr(self, 'tag', None)
            if tag is not None:
                url = url + 'tag/' + tag
            yield scrapy.Request(url, self.parse)
    
        def parse(self, response):
            for quote in response.css('div.quote'):
                yield {
                    'text': quote.css('span.text::text').get(),
                    'author': quote.css('small.author::text').get(),
                }
    
            next_page = response.css('li.next a::attr(href)').get()
            if next_page is not None:
                yield response.follow(next_page, self.parse)
    如果您将tag=humor参数传递给此蜘蛛,您会注意到它只会访问humor标记中的URL ,例如 http://quotes.toscrape.com/tag/humor。
    
    蜘蛛可以在__init__方法中访问参数:
    
    import scrapy
    
    class MySpider(scrapy.Spider):
        name = 'myspider'
    
        def __init__(self, category=None, *args, **kwargs):
            super(MySpider, self).__init__(*args, **kwargs)
            self.start_urls = ['http://www.example.com/categories/%s' % category]
            # ...
    通用蜘蛛
    Scrapy附带了一些有用的通用蜘蛛,您可以使用这些蜘蛛来对您的蜘蛛进行子类化。他们的目的是为一些常见的抓取案例提供方便的功能,例如根据特定规则跟踪站点上的所有链接,从站点地图抓取或解析XML / CSV Feed。
    
    对于以下蜘蛛中使用的示例,我们假设您有一个TestItem在myproject.items模块中声明的项目:
    
    import scrapy
    
    class TestItem(scrapy.Item):
        id = scrapy.Field()
        name = scrapy.Field()
        description = scrapy.Field()
    抓取蜘蛛
    类scrapy.spiders.CrawlSpider
    这是用于抓取常规网站的最常用的蜘蛛,因为它通过定义一组规则为跟踪链接提供了便利的机制。它可能不是最适合您的特定网站或项目,但它在几种情况下足够通用,因此您可以从它开始并根据需要覆盖它以获得更多自定义功能,或者只是实现您自己的蜘蛛。
    
    除了从Spider继承的属性(您必须指定)之外,此类还支持一个新属性:
    
    rules
    这是一个(或多个)Rule对象的列表。每个都Rule 定义了爬网站点的特定行为。规则对象如下所述。如果多个规则匹配相同的链接,则将根据它们在此属性中定义的顺序使用第一个规则。
    
    这个蜘蛛还暴露了一个可重写的方法:
    
    parse_start_url(回应)
    为start_urls响应调用此方法。它允许解析初始响应,并且必须返回 Item对象,Request 对象或包含其中任何一个的iterable。
    
    爬行规则
    class scrapy.spiders.Rule(link_extractor,callback = None,cb_kwargs = None,follow = None,process_links = None,process_request = None )
    link_extractor是一个Link Extractor对象,它定义如何从每个已爬网页面中提取链接。
    
    callback是一个可调用的或一个字符串(在这种情况下,将使用来自具有该名称的spider对象的方法)为使用指定的link_extractor提取的每个链接调用。此回调接收响应作为其第一个参数,并且必须返回包含Item和/或 Request对象(或其任何子类)的列表。
    
            
    CrawlSpider示例
    现在让我们看看带有规则的示例CrawlSpider:
    
    import scrapy
    from scrapy.spiders import CrawlSpider, Rule
    from scrapy.linkextractors import LinkExtractor
    
    class MySpider(CrawlSpider):
        name = 'example.com'
        allowed_domains = ['example.com']
        start_urls = ['http://www.example.com']
    
        rules = (
            # Extract links matching 'category.php' (but not matching 'subsection.php')
            # and follow links from them (since no callback means follow=True by default).
            Rule(LinkExtractor(allow=('category.php', ), deny=('subsection.php', ))),
    
            # Extract links matching 'item.php' and parse them with the spider's method parse_item
            Rule(LinkExtractor(allow=('item.php', )), callback='parse_item'),
        )
    
        def parse_item(self, response):
            self.logger.info('Hi, this is an item page! %s', response.url)
            item = scrapy.Item()
            item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (d+)')
            item['name'] = response.xpath('//td[@id="item_name"]/text()').get()
            item['description'] = response.xpath('//td[@id="item_description"]/text()').get()
            return item
    这个蜘蛛会开始抓取example.com的主页,收集类别链接和项链接,使用该parse_item方法解析后者。对于每个项目响应,将使用XPath从HTML中提取一些数据,并将Item使用它填充。
    
    XMLFeedSpider 
    而怎样创建呢
    scrapy genspider -l
    就能看到一系列
    再通过scrapy genspider -t xmlfeed [name] [域名]
    j就可以了
    而且xmlfeedspider自带parse_node就像自带的普通爬虫项目的parse一样
    类scrapy.spiders.XMLFeedSpider
    XMLFeedSpider用于通过按某个节点名称迭代XML feed来解析XML feed。迭代器可以选自:iternodes,xml,和html。iternodes出于性能原因,建议使用迭代器,因为xml和html迭代器一次生成整个DOM以便解析它。但是,在使用html错误标记解析XML时,使用迭代器可能很有用。
    
    要设置迭代器和标记名称,必须定义以下类属性:
    
    iterator
    一个字符串,它定义要使用的迭代器。它可以是:
    
    'iternodes' - 基于正则表达式的快速迭代器
    'html'- 使用的迭代器Selector。请记住,这使用DOM解析,并且必须在内存中加载所有DOM,这可能是大型Feed的问题
    'xml'- 使用的迭代器Selector。请记住,这使用DOM解析,并且必须在内存中加载所有DOM,这可能是大型Feed的问题
    它默认为:'iternodes'。
    
    itertag
    一个字符串,其中包含要迭代的节点(或元素)的名称。示例:
    
    itertag = 'product'
    namespaces
    一个元组列表,用于定义将使用此spider处理的该文档中可用的名称空间。的 和将被用于自动注册使用的命名空间 的方法。(prefix, uri)prefixuriregister_namespace()
    
    然后,您可以在itertag 属性中指定具有名称空间的节点。
    
    例:
    
    class YourSpider(XMLFeedSpider):
    
        namespaces = [('n', 'http://www.sitemaps.org/schemas/sitemap/0.9')]
        itertag = 'n:url'
        # ...
    除了这些新属性外,此蜘蛛还具有以下可重写方法:
    
    adapt_response(回应)
    在蜘蛛开始解析之前,一旦从蜘蛛中间件到达就接收响应的方法。它可以在解析之前用于修改响应主体。此方法接收响应并返回响应(可能是相同或另一个)。
    
    parse_node(响应,选择器)
    对于与提供的标记名称(itertag)匹配的节点,调用此方法。接收Selector每个节点的响应和响应 。必须覆盖此方法。否则,你的蜘蛛将无法正常工作。此方法必须返回Item对象, Request对象或包含其中任何对象的iterable。
    
    process_results(回应,结果)
    为蜘蛛返回的每个结果(项目或请求)调用此方法,并且它旨在执行将结果返回到框架核心之前所需的任何上次处理,例如设置项目ID。它会收到一个结果列表以及产生这些结果的响应。它必须返回结果列表(项目或请求)。
    
    XMLFeedSpider示例
    这些蜘蛛很容易使用,让我们来看一个例子:
    class MyxmlspiderSpider(XMLFeedSpider):
        name = 'myxmlspider'
        allowed_domains = ['sina.com.cn']
        start_urls = ['http://blog.sina.com.cn/rss/1615888477.xml']
        iterator = 'iternodes' # you can change this; see the docs
        itertag = 'rss' # change it accordingly
    
        def parse_node(self, response, node):
            # item = {}
            i=MyxmlItem()#在item里面定义好了的
            #item['url'] = selector.select('url').get()
            #item['name'] = selector.select('name').get()
            #item['description'] = selector.select('description').get()
            i['title']=node.xpath('/rss/channel/item/title/text()').extract()
            i['link']=node.xpath('rss/channel/item/link/text()').extract()
            i['author']=node.xpath('rss/channel/item/author/text()').extract()
            for j in range(len(i['title'])):
                print('第'+str(j+1)+'篇文章')
                print('标题是:')
                print(i['title'][j])
                print('对应的链接是:')
                print(i['link'][j])
                print('对应的作者是:')
                print(i['author'][j])
                print('===============')
            return i
    
    
    
    from scrapy.spiders import XMLFeedSpider
    from myproject.items import TestItem
    
    class MySpider(XMLFeedSpider):
        name = 'example.com'
        allowed_domains = ['example.com']
        start_urls = ['http://www.example.com/feed.xml']
        iterator = 'iternodes'  # This is actually unnecessary, since it's the default value
        itertag = 'item'
    
        def parse_node(self, response, node):
            self.logger.info('Hi, this is a <%s> node!: %s', self.itertag, ''.join(node.getall()))
    
            item = TestItem()
            item['id'] = node.xpath('@id').get()
            item['name'] = node.xpath('name').get()
            item['description'] = node.xpath('description').get()
            return item
    基本上我们在那里做的是创建一个蜘蛛,从给定的下载源start_urls,然后遍历每个item标签,打印出来,并存储一些随机数据Item。
    
    CSVFeedSpider 
    类scrapy.spiders.CSVFeedSpider
    这个蜘蛛与XMLFeedSpider非常相似,只不过它遍历行而不是节点。在每次迭代中调用的方法是parse_row()。
    
    delimiter
    CSV文件中每个字段的分隔符字符串默认为','(逗号)。
    
    quotechar
    带有CSV文件中每个字段的机箱字符的字符串默认为'"'(引号)。
    
    headers
    CSV文件中的列名列表。
    
    parse_row(响应,行)
    使用CSV文件的每个提供(或检测到的)标头的密钥接收响应和dict(表示每行)。该蜘蛛还提供了覆盖adapt_response和process_results用于预处理和后处理目的的方法的机会。
    
    CSVFeedSpider示例
    scrapy genspider -t csvfeed mycsvspider iqianyue.com
    让我们看一个与前一个类似的示例,但使用 CSVFeedSpider:
    
    from scrapy.spiders import CSVFeedSpider
    from myproject.items import TestItem
    
    class MySpider(CSVFeedSpider):
        name = 'example.com'
        allowed_domains = ['example.com']
        start_urls = ['http://www.example.com/feed.csv']
        delimiter = ';'
        quotechar = "'"
        headers = ['id', 'name', 'description']
    
        def parse_row(self, response, row):
            self.logger.info('Hi, this is a row!: %r', row)
    
            item = TestItem()
            item['id'] = row['id']
            item['name'] = row['name']
            item['description'] = row['description']
            return item
    
    在项目之间共享根目录
    项目根目录(包含该目录的目录)scrapy.cfg可以由多个Scrapy项目共享,每个项目都有自己的设置模块。
    
    在这种情况下,你必须定义下这些设置模块的一个或多个别名[settings]在您的scrapy.cfg文件:
    
    [settings]
    default = myproject1.settings
    project1 = myproject1.settings
    project2 = myproject2.settings
    默认情况下,scrapy命令行工具将使用这些default设置。使用SCRAPY_PROJECT环境变量指定scrapy要使用的其他项目:
    
    $ scrapy settings --get BOT_NAME
    Project 1 Bot
    $ export SCRAPY_PROJECT=project2
    $ scrapy settings --get BOT_NAME
    Project 2 Bot
    

    项目管道
    点击这里还可以去笔记o
    这个主要参看这个笔记 ,里面有源码

    在一个项目被蜘蛛抓取后,它被发送到项目管道,该项目管道通过顺序执行的几个组件处理它。
    
    每个项目管道组件(有时简称为“项目管道”)是一个实现简单方法的Python类。他们收到一个项目并对其执行操作,同时决定该项目是否应继续通过管道或被丢弃并且不再处理。
    
    项目管道的典型用途是:
    
    清理HTML数据
    验证已删除的数据(检查项目是否包含某些字段)
    检查重复项(并删除它们)
    将已删除的项目存储在数据库中
    process_item(self, item, spider)
    处理item
    open_spider(self, spider)
    打开蜘蛛时会调用此方法。
    如
    from scrapy.exceptions import DropItem
    import pymongo
    
    class TextPipeline(object):
        def __init__(self):
            self.limit=50
    
        def process_item(self, item, spider):
            if item['text']:
                if len(item['text'])>self.limit:
                    item['text']=item['text'][0:self.limit].rstrip()+'........' #rstrip去除空格
                    return item
                else:
                    return DropItem('miss Text')
    
    #官网里有这些代码
    class MongoPipeline(object):
        def __init__(self,mongo_url,mongo_db):
            self.mongo_url=mongo_url
            self.mongo_db=mongo_db
    
        @classmethod
        def from_crawler(cls,crawler):
            return cls(
                mongo_url=crawler.settings.get('MONGO_URL'),
                mongo_db=crawler.settings.get('MONGO_DB')
            )
        def open_spider(self,spider):
            self.client=pymongo.MongoClient(self.mongo_url)
            self.db=self.client[self.mongo_db]
    
        def process_item(self,item,spider):
            name=item.__class__.__name__
            self.db[name].insert(dict(item))
            return item
    
        def close_spider(self,spider):
            self.client.close()
    并设置好setting 
            ITEM_PIPELINES = {
        'quote.pipelines.TextPipeline': 300,
        'quote.pipelines.MongoPipeline': 400
    }
    spiders下面与init同级添加一个yuotes.py
    import scrapy
    from quote.items import QuoteItem
    
    class QuotesSpider(scrapy.Spider):
        name = 'quotes'
        allowed_domains = ['quotes.toscrape.com']
        start_urls = ['http://quotes.toscrape.com/']
    
        def parse(self, response):
            quotes=response.css('.quote')         #.quote是pyquery的特点
            for quote in quotes:
                item=QuoteItem()
                text=quote.css('.text::text').extract_first()
                author=quote.css('.author::text').extract_first()
                tags=quote.css('.tags .tag::text').extract()  #所有结果,多个内容,类似于findall
                item['text'] = text
                item['author']=author
                item['tags']=tags
                yield item
            next =response.css('.pager .next a::attr(href)').extract_first()  #这个可以参看f12里面的 是两个class
            url=response.urljoin(next) #可以生成一个完整的url因为是不完整的比如少http://等
            yield scrapy.Request(url=url,callback=self.parse)  #递归,自己回调自己
    items里
    class QuoteItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        text=scrapy.Field()
        author=scrapy.Field()
        tags=scrapy.Field()
    

    download  middlewer
    点击这里[downloader主页](https://docs.scrapy.org/en/latest/topics/downloader-middleware.html "崔庆才")o
    download  middlewer
    点击这里[downloader崔庆才视频](https://www.bilibili.com/video/av19057145/?p=28 "崔庆才")o
    

    Scrapy批量运行爬虫文件的两种方法:

    1、使用CrawProcess实现

    https://doc.scrapy.org/en/latest/topics/practices.html

    2、修改craw源码+自定义命令的方式实现
    crawl命令的源码文件在scrapy官方的github项目中找到(地址是:https://github.com/scrapy/scrapy/blob/master/scrapy/commands/crawl.py

    (1)我们打开scrapy.commands.crawl.py 文件可以看到:
    
        def run(self, args, opts):
            if len(args) < 1:
                raise UsageError()
            elif len(args) > 1:
                raise UsageError("running 'scrapy crawl' with more than one spider is no longer supported")
            spname = args[0]
     
            self.crawler_process.crawl(spname, **opts.spargs)
            self.crawler_process.start()
    这是crawl.py 文件中的run() 方法,在此可以指定运行哪个爬虫,要运行所有的爬虫,则需要更改这个方法。
    
    run() 方法中通过crawler_process.crawl(spname, **opts.spargs) 实现了爬虫文件的运行,spname代表爬虫名。要运行多个爬虫文件,首先要获取所有的爬虫文件,可以通过crawler_process.spider_loader.list() 实现。
    如何获取所有的爬虫文件,如果要获取所有的爬虫文件,可以通过crawler_process.crawl(spname, **opts.spargs) 实现。
    
    在这里,我们将新文件夹的命名为mycmd,在对应目录下创建该文件夹(位置在spiders目录的同级目录下),如下所示:
    
    cd .mymultispd
    mkdir mycmd
    创建好文件夹再创建一个.py文件
    复制下面代码
    
    import os
    from scrapy.commands import ScrapyCommand
    from scrapy.utils.conf import arglist_to_dict
    from scrapy.utils.python import without_none_values
    from scrapy.exceptions import UsageError
     
     
    class Command(ScrapyCommand):
     
        requires_project = True
     
        def syntax(self):
            return "[options] <spider>"
     
        def short_desc(self):
            return "Run a spider"
     
        def add_options(self, parser):
            ScrapyCommand.add_options(self, parser)
            parser.add_option("-a", dest="spargs", action="append", default=[], metavar="NAME=VALUE",
                              help="set spider argument (may be repeated)")
            parser.add_option("-o", "--output", metavar="FILE",
                              help="dump scraped items into FILE (use - for stdout)")
            parser.add_option("-t", "--output-format", metavar="FORMAT",
                              help="format to use for dumping items with -o")
     
        def process_options(self, args, opts):
            ScrapyCommand.process_options(self, args, opts)
            try:
                opts.spargs = arglist_to_dict(opts.spargs)
            except ValueError:
                raise UsageError("Invalid -a value, use -a NAME=VALUE", print_help=False)
            if opts.output:
                if opts.output == '-':
                    self.settings.set('FEED_URI', 'stdout:', priority='cmdline')
                else:
                    self.settings.set('FEED_URI', opts.output, priority='cmdline')
                feed_exporters = without_none_values(
                    self.settings.getwithbase('FEED_EXPORTERS'))
                valid_output_formats = feed_exporters.keys()
                if not opts.output_format:
                    opts.output_format = os.path.splitext(opts.output)[1].replace(".", "")
                if opts.output_format not in valid_output_formats:
                    raise UsageError("Unrecognized output format '%s', set one"
                                     " using the '-t' switch or as a file extension"
                                     " from the supported list %s" % (opts.output_format,
                                                                      tuple(valid_output_formats)))
                self.settings.set('FEED_FORMAT', opts.output_format, priority='cmdline')
     
        def run(self, args, opts):
            if len(args) < 1:
                raise UsageError()
            elif len(args) > 1:
                raise UsageError("running 'scrapy crawl' with more than one spider is no longer supported")
            spname = args[0]
     
            self.crawler_process.crawl(spname, **opts.spargs)
            self.crawler_process.start()
    再修改run
    首先,将crawl命令的源码复制到该文件(mycrawl.py)中,然后进行修改:
     
        #主要修改这里
        def run(self, args, opts):
            #获取爬虫列表
            spd_loader_list=self.crawler_process.spider_loader.list()
            #遍历各爬虫
            for spname in spd_loader_list or args:
                self.crawler_process.crawl(spname, **opts.spargs)
                print("此时启动的爬虫为:"+spname)
            self.crawler_process.start()
    
    然后,可以新建的该源代码文件的同级目录下添加一个初始化文件__init__.py,如下所示:
    COMMANDS_MODULE = 'hell_scrapy.mycmd'
    并添加进setting
    COMMANDS_MODULE = 'hell_scrapy.mycmd'
    随后,在命令行进入该项目所在的目录,并输入scrapy -h,出现如下所示的信息:
    Available commands:
      bench         Run quick benchmark test
      check         Check spider contracts
      cmd           Run all spider
      crawl         Run a spider
      edit          Edit spider
      fetch         Fetch a URL using the Scrapy downloader
      genspider     Generate new spider using pre-defined templates
      list          List available spiders
      parse         Parse URL (using its spider) and print the results
      runspider     Run a self-contained spider (without creating a project)
      settings      Get settings values
      shell         Interactive scraping console
      startproject  Create new project
      version       Print Scrapy version
      view          Open URL in browser, as seen by Scrapy
    发现有cmd 就是自己创建的.py文件,说明OK拉
    再执行scrapy cmd --nolog
    结果为
    
    此时启动的爬虫为:myxmlspider
    此时启动的爬虫为:weisuen
    第1篇文章
    标题是:
    精通Python网络爬虫-新书介绍
    对应的链接是:
    [<Selector xpath='/html/head/title/text()' data='京东(JD.COM)-正品低价、品质保障、配送及时、轻松购物!'>]
    [<Selector xpath='/html/head/title/text()' data='新浪首页'>]
    
    

    scrapy 避免被禁止


    1.禁止cookie
    有的网页会通过用户的cookie信息进行识别和分析,此时我们可以通过禁用本地cookie从而让对方网站无法识别
    如何禁止呢
    在对应的scrapy项目的setting 中
    打开发现有这两行代码
    # Disable cookies (enabled by default)
    #COOKIES_ENABLED = False
    只需要把
    #COOKIES_ENABLED = False
    注释取消就ok拉
    # Disable cookies (enabled by default)
    COOKIES_ENABLED = False
    
    2.设置下载延时
    有的网站通过访问的频率分析的
    同样这样的设置在setting 里
    # Configure a delay for requests for the same website (default: 0)
    # See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
    # See also autothrottle settings and docs
    #DOWNLOAD_DELAY = 3
    只需要把
    DOWNLOAD_DELAY = 3
    注释取消就Ok 拉,时间还可以自己设置
    3就是三秒
    

    3.使用ip代理池
    如果同一个ip在短时间对服务器网页进行爬取,就会被禁止
    所以 我们可以为scrapy项目建立一个下载中间件,在setting中配置好下载中间件并配置ip池
    首先我们创建一个.py文件,由于我们需要大量的ip 所以可以在
    http://yum.iqianyue.com/proxy里去找

    找到这些ip后,我们在setting里面添加如下
    #ip池设置
    IPPOOL=[
        {'ipaddr':'121.33.24.2...'},
        {'ipaddr':'121.33.24.2...'},
        {'ipaddr':'121.33.24.2...'},
        {'ipaddr':'121.33.24.2...'},
        {'ipaddr':'121.33.24.2...'},
    ]
    此时,IPPOOL就是对应的代理服务器的ip池
    设置好ip池后,我们需要编写下载中间件文件,也就是我们先前创建的.py文件
    在scrapy中,与代理服务器设置相关的下载中间件事HttpProxyMiddleware
    所以详细 参看官方文档
    import random
    from hell_scrapy.setting import IPPOOL
    from scrapy.contrb.downloadermiddleware.httpproxy import HttpProxyMiddleware
    
    class IPPOOLS(HttpProxyMiddleware):
        def __init__(self,ip=''):
            self.ip=ip
        def process_request(self,request,spider):
            this_ip=random.choice(IPPOOL)
            print('当前选择的ip是:'+this_ip['ipaddr])
            request.meta['proxy']='http://'+this_ip['ipaddr']
    编写好后,由于这只是一个普通middle.py文件,所以我们需要在setting中配置下
    #DOWNLOADER_MIDDLEWARES = {
    #    'hell_scrapy.middlewares.HellScrapyDownloaderMiddleware': 543,
    #}
    更改为
    DOWNLOADER_MIDDLEWARES = {
    #    'hell_scrapy.middlewares.HellScrapyDownloaderMiddleware': 543,
    'scrapy.contrb.downloadermiddleware.httpproxy.HttpProxyMiddleware':123 #根据官方文档配置这个
    'hell_scrapy.middle.IPPOOLS':125
    }
    配置好了后运行scrapy crawl weisuen --nolog  ok 拉
    
    

    scrapy实战

    创建项目scrapy startproject name

    item编写
    这里是我们想要的信息
    class AutopjtItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        name=scrapy.Field()
        price=scrapy.Field()
        link=scrapy.Field()
        comnum=scrapy.Field()
    
    pipeline编写
    这里是存蓄
    import json
    import codecs
    
    class AutopjtPipeline(object):
        def __init__(self):
            self.file=codes.open('D:Python_codescrapy_envautopjtmydata','wb',encoding='utf-8')
        def process_item(self, item, spider): #听名字就知道这是处理item的函数,当然返回的也是处理后的item
            i=json.dumps(dict(item),ensure_ascii=False)
            line=i+'
    '
            self.file.write(line)
            return item
        def close_spider(self,spider):
            self.file.close()
    
    srtting 编写
    打开item_pipelines
    打开cookie
    将robotstxt设置fasle
    

    这时出现一点小错误,没有库
    解决是打开setting找到虚拟环境,用已存在的虚拟scrapy_env就OK拉

    自动爬虫的编写
    scrapy genspider -t basic autospd dangdang.com 依据的模板是basic不是xmlfeed等其他
    import scrapy
    from autopjt.items import AutopjtItem
    from scrapy.http import Request
    class AutospdSpider(scrapy.Spider):
        name = 'autospd'
        allowed_domains = ['dangdang.com']
        start_urls = ['http://search.dangdang.com/?key=%BB%A8%C9%FA%D3%CD&act=input&page_index=1']
    
        def parse(self, response):
            item=AutopjtItem()
            #
            item['name']=response.xpath("//a[@class='pic']/@title").extract()
            item['price']=response.xpath("//span[@class='price_n']/text()").extract()
            item['link']=response.xpath("//a[@class='pic']/@href").extract()
            item['comnum']=response.xpath("//a[@name='P_p1']/text()").extract()
            yield item
            for i in range(1.5):
                url='http://search.dangdang.com/?key=%BB%A8%C9%FA%D3%CD&act=input&page_index='+str(i)
                yield Request(url,callback=self.parse)
    
    这是源码
    <a title=" 美临 小榨花生油 5L 浓香花生油" ddclick="act=normalResult_picture&amp;pos=1352623776_0_1_q" class="pic" name="itemlist-picture" dd_name="单品图片" href="http://product.dangdang.com/1352623776.html" target="_blank"><img src="http://img3m6.ddimg.cn/42/13/1352623776-1_b_1.jpg" alt=" 美临 小榨花生油 5L 浓香花生油"><p class="cool_label"></p></a>
    <p class="price"> <span class="price_n">¥128.00</span></p>
    <p class="name" name="title"><a title=" 美临 小榨花生油 5L 浓香花生油" href="http://product.dangdang.com/1352623776.html" name="itemlist-title" dd_name="单品标题" ddclick="act=normalResult_title&amp;pos=1352623776_0_1_q" target="_blank"> 美临 小榨<font class="skcolor_ljg">花生油</font> 5L 浓香<font class="skcolor_ljg">花生油</font></a></p>
    <p class="link"><a href="http://shop.dangdang.com/21079" name="itemlist-shop-name" dd_name="单品店铺" target="_blank" title="美临旗舰店">美临旗舰店</a></p>
    <p class="star"><span class="level"><span style=" 100%;"></span></span><a href="http://product.dangdang.com/1352623776.html?point=comment_point" target="_blank" name="itemlist-review" dd_name="单品评论" ddclick="act=click_review_count&amp;pos=1352623776_0_1_q">333条评论</a></p>
    

    crawlspider

    item
        name=scrapy.Field()
        link=scrapy.Field()
    
    pipeline
    class CrawlPipeline(object):
        def process_item(self, item, spider):
            print(item['name'])
            print(item['link'])
            print('--------------')
            return item
    
    
    scrapy genspider -l查看
    有crawlspider
    然后scrapy gendpider -t crawl name sohu.com
    
    from crawl.items import CrawlItem
    
    class CrawlspiderSpider(CrawlSpider):
        name = 'crawlspider'
        allowed_domains = ['sohu.com']
        start_urls = ['http://www.sohu.com/']
    
        # rules = (
        #     Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
        # )
        rules = (
            Rule(LinkExtractor(allow=('.*?/n.*?shtml'), allowed_domains=('sohu.com')), follow=True),
        )
        def parse_item(self, response):
            i=CrawlItem()
            i['name']=response.xpath("/html/head/title/text()").extract()
            i['link']=response.xpath("//link[@rel='canonical']/@href").extract()
            #item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
            #item['name'] = response.xpath('//div[@id="name"]').get()
            #item['description'] = response.xpath('//div[@id="description"]').get()
            return i
    
    
  • 相关阅读:
    2019-2020-1 20191312《信息安全专业导论》第十二周学习总结
    GPG
    2019-2020-1 20191312《信息安全专业导论》第十一周学习总结
    wireshark
    ssh
    Nmap
    2019-2020-1 《python程序设计》20192428魏来 综合实践报告
    20192428 魏来 2019-2020《Python程序设计》 实验三 报告
    20192428 实验二《Python程序设计》实验报告
    20192428 实验一《Python程序设计》实验报告
  • 原文地址:https://www.cnblogs.com/yangj-Blog/p/13123636.html
Copyright © 2020-2023  润新知