Python学习内容整理

Scrapy学习笔记

2020-02-07  本文已影响0人  Lorence

爬虫的项目结构

  1. items.py: 用来存放爬虫爬取下来的数据的模型。有固定的格式。

  2. middlewares.py: 用于存放各种中间的文件。

  3. pipelines.py: 用于将items的模型存储到本地磁盘中。

  4. settings.py: 本爬虫的一些配置信息。例如,浏览器的请求头,多久发送一次请求,ip代理等。

  5. scrapy.cfg: 项目的配置文件。

  6. spider包: 以后所有的爬虫,都是存放在这个里面。


每个文件结构里面的一些注意事项

1. item.py

建议在items.py中定义好模型,以后就不用使用字典定义了。其中模型定义的写法是固定的,例如:

class PriscillaItem(scrapy.Item): 
  Author=scrapy.Field() 
  Content=scrapy.Field()

定义好模型后,在spider文件中,首先要引用该模型,写入例如:
from Priscilla.items import PriscillaItem
随后把抓取的内容,返回对应的模型类型,并用yield返回到pipelines.py中。写法例子如下:

item=PriscillaItem(Author=author,Content=content) 
yield item

2. pipeline.py

这是专门用来保存数据的,其中有三个常用方法需要定义:

注意,需要激活pipeline才能正常使用,在settings.py中,设置ITEM_PIPELINES.
ITEM_PIPELINES = {'Priscilla.pipelines.PriscillaPipeline': 300,}
下面代码是pipeline.py中的例子:

import json
class PriscillaPipeline(object):
    def __init__(self):
        self.fp=open("duanzi.json",'w',encoding='utf-8')

    def open_spider(self,spider):
        print("爬虫开始")

    def process_item(self, item, spider):
        item_json=json.dumps(dict(item),ensure_ascii=False)
        self.fp.write(item_json+'\n')
        return item

    def close_spider(self, spider):
        self.fp.close()
        print("爬虫结束了")

3. 写爬虫时遇到的其他坑:


4. Scrapy CSS选择器的使用方法 (学习的难点,经常搞混)

1. 标签属性值的提取

href的值URL的提取:这是最常见的,我们要进入下一页、或是打开内容页……都少不了URL值,如下面这段HTML,我们来提取一下里面的UR:

<ol class="page-navigator">
  <li class="current"><a href="http://lab.scrapyd.cn/page/1/">1</a></li>
  <li><a href="http://lab.scrapyd.cn/page/2/">2</a></li>
  <li><a href="http://lab.scrapyd.cn/page/3/">3</a></li>
  <li><a href="http://lab.scrapyd.cn/page/4/">4</a></li>
</ol>

提取属性我们是用:“标签名::attr(属性名)”,比如我们要提取url表达式就是:a::attr(href),要提取图片地址的表达式就是:img::attr(src)……以此类推。
方法是找到我们要提取目标最近的class或是id,可以看到这段代码中有个class="page-navigator",那我们就可以这样来写:
response.css(".page-navigator a::attr(href)").extract()
当这样限定之后,就成功提取了想要的URL,
解释上面的:".page-navigator",其中点代表class选择器,
如果代码中是:id="page-navigator",那我们这里就要写成:"#page-navigator"。

再来一个提取标签属性的栗子,最常见的就是我们的图片地址,也就是要提取图片的src值,如下面网页:

<article class="post" itemscope="" itemtype="http://schema.org/BlogPosting">
        <h1 class="post-title" itemprop="name headline"><a itemprop="url" href="http://lab.scrapyd.cn/archives/57.html">中国传世名画</a></h1>
        <div class="post-content" itemprop="articleBody">
            <p>看官,此页面只为爬虫练习使用,都是残卷,若喜欢可以去找点高清版!</p>
            <p><img src="http://lab.scrapyd.cn/usr/uploads/2018/02/3875934880.jpg" alt="1.jpg" title="1.jpg"></p>
                        <p><img src="http://lab.scrapyd.cn/usr/uploads/2018/02/2269613152.jpg" alt="2.jpg" title="2.jpg"></p>
            <p><img src="http://lab.scrapyd.cn/usr/uploads/2018/02/2360992798.jpg" alt="3.jpg" title="3.jpg"></p>
            <p><img src="http://lab.scrapyd.cn/usr/uploads/2018/02/2239103416.jpg" alt="4.jpg" title="4.jpg"></p>
            <p><img src="http://lab.scrapyd.cn/usr/uploads/2018/02/4145232684.jpg" alt="5.jpg" title="5.jpg"></p>        
        </div>
        <p itemprop="keywords" class="tags">标签: <a href="http://lab.scrapyd.cn/tag/%E8%89%BA%E6%9C%AF/">艺术</a>, <a href="http://lab.scrapyd.cn/tag/%E5%90%8D%E7%94%BB/">名画</a></p>
    </article>

首先找到隔img最近的class或id,可以看到有个:class="post-content",于是我们可以这样写表达式:
response.css(".post-content img::attr(src)").extract()

上面便是提取标签属性的方法,利用的就是:标签名::attr(属性名),关键点就是如何缩小范围!


2. 标签内容的提取

<div class="left">
  scrapy中文网左边
</div>

<div class="center">
  scrapy中文网中部
</div>

<div class="right">
  scrapy中文网右侧
</div>

如果我们要提取第二个div里面的内容,找到最近的class=“center”,最终表达式如下:
response.css(".center::text").extract()
这样的话就能正确提取我们想要的内容;下面我们再介绍一个最常用的提取方式:含有嵌套标签文字的提取,HTML如下:

<div class="post-content" itemprop="articleBody">
  <p>如果你因失去了太阳而流泪,那么你也将失去群星了。 <br>
    If you shed tears when you miss the sun, you also miss the stars. 
   </p>
   <p>
    <a href="http://www.scrapyd.cn">scrapy中文网(</a><a href="http://www.scrapyd.cn">http://www.scrapyd.cn</a>)整理 
   </p>       
 </div>

如果我们要提取class=“post-content”里面的所有文字,
response.css(".post-content *::text").extract()
可以看到,“::tex“t前面有个“*”号,代表选择所有元素。


5. 提取数据之:xpath选择器

XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。 下面列出了最有用的路径表达式:

1. scrapy xpath 属性提取

函数:response.xpath("表达式"),提取属性的话既然使用:@
"//ol//@href",这个表达式表示:ol标签下所有的href属性值,可以看到我们这里限定了html的<ol>标签,这里的话页面只有一个<ol>,不会出错,如果页面中有多个<ol>,那就不一定能得到我们想要的结果,那如何是好?这里我们还能限定我们的属性,使用的是:
标签[@属性名='属性值']
例如,我们分页标签:

<ol class="page-navigator">
  ……
</ol>

里面有个:class=“page-navigator”,那我们就可以这样限制://ol[@class="page-navigator"]//@href 好了,这样的话就能让<ol>尽量缩小范围
如果这里的属性是id那就:ol[@id='page-navigator']

2. 提取标签里面的内容,表达式: //text()

例如,如果你要提取首页右侧的标签,如下:

<ul class="tags-list">
        <li><a style="color:rgb(101,86,
           72)" href="http://lab.scrapyd.cn/tag/%E4%BA%BA%E7%94%9F/">
         人生</a></li>
        <li><a style="color:rgb(214,236,
           5)" href="http://lab.scrapyd.cn/tag/%E5%8A%B1%E5%BF%97/">
         励志</a></li>
         ……
        <li><a style="color:rgb(4,4,
           41)" href="http://lab.scrapyd.cn/tag/%E7%BB%9D%E4%B8%96%E5%A5%BD%E8%AF%8D/">
         绝世好词</a></li>
        <li><a style="color:rgb(204,12,
           225)" href="http://lab.scrapyd.cn/tag/%E6%9C%A8%E5%BF%83/">
         木心</a></li>
        ……
        <li><a href="http://lab.scrapyd.cn">返回首页</a></li>
<li><a href="http://bbs.scrapyd.cn" target="_blank">SCRAPY中文社区</a></li>
    <li><a href="http://www.scrapyd.cn" target="_blank">SCRAPY中文网</a></li>
</ul>

可以看到标签文字是在 "class=tags-list" 的<ul>里面,那我们就可以这样写表达式://ul[@class='tags-list']//a//text()


3. 包含HTML标签的所有文字内容提取:string()

例如,我们要提取div里面的所有文字:

<div class="post-content" itemprop="articleBody">
       <p>如果你因失去了太阳而流泪,那么你也将失去群星了。 
      <br>If you shed tears when you miss the sun, you also miss the stars. 
      </p>
      <p><a href="http://www.scrapyd.cn">[<u style="box-sizing: border-box;">scrapy中文网</u>](http://www.scrapyd.cn/)(</a><a href="http://www.scrapyd.cn">http://www.scrapyd.cn</a>)整理</p>        
</div>

如果我们用表达式://div[@class='post-content']//text(),你会发现虽然能提取但是一个列表,不是整段文字:

In [4]: response.xpath("//div[@class='post-content']//text()").extract()
Out[4]:
['\n            ',
 '如果你因失去了太阳而流泪,那么你也将失去群星了。 ',
 'If you shed tears when you miss the sun, you also miss the stars. ',
 'scrapy中文网(',
 'http://www.scrapyd.cn',
 ')整理',
 '        ']

那这里我们就用到一个xpath函数:string(),我们可以把表达式这样写:response.xpath("string(//div[@class='post-content'])").extract(),可看到我们没有使用:text(),而是用:string(要提取内容的标签),这样的话就能把数据都提取出来了,而且都合成为一条,并非一个列表,如下:

In [5]: response.xpath("string(//div[@class='post-content'])").extract()
Out[5]: ['\n            如果你因失去了太阳而流泪,那么你也将失去群星了。 If you
shed tears when you miss the sun, you also miss the stars. scrapy中文网(http://
www.scrapyd.cn)整理        ']

这一种用法在我们提取商品详情、小说内容的时候经常用到


4.xpath例子:

路径表达式 结果
/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。
bookstore 选取 bookstore 元素的所有子节点。
/bookstore 选取根元素 bookstore。
注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!

bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。
//book 选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang 选取名为 lang 的所有属性。

XPath 通配符可用来选取未知的 HTML元素。
通配符 描述
* 匹配任何元素节点。
@* 匹配任何属性节点。
node() 匹配任何类型的节点。
/bookstore/* 选取 bookstore 元素的所有子元素。
//* 选取文档中的所有元素。
//title[@*] 选取所有带有属性的 title 元素。

上一篇 下一篇

猜你喜欢

热点阅读