自学Python十二 战斗吧Scrapy!

  初窥Scrapy

  Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。

还是先推荐几个学习的教程:Scrapy 0.25文档  Scrapy快速入门教程 这些教程里面有关于Scrapy的安装,创建项目,爬取实例等等,如果一个全新的东西扔给你首先要看文档,初看文档我也是蒙蒙的,后来一层一层的去摸索才大概懂了个皮毛。我们就试着将之前的爬虫福利改写成用Scrapy框架的爬虫,在实践中学习。 战斗吧 Scrapy!

  安装Scrapy

  如果配置好了pip或者easy_install 可以直接pip install scrapy (从https://pip.pypa.io/en/latest/installing.html 安装 pip

  还需要从 http://sourceforge.net/projects/pywin32/ 安装 pywin32 (注:此处要注意了,这里pywin32的版本要跟你python的完全一致,比如你在64位系统安装的32位的python2.7 那么你也需要安装2.7 32位的pywin32) 否则遇到:Scrapy [twisted] CRITICAL:Unhandled error in Deferred

  新建项目

  因为我们要重写之前的项目,我们新建一个scrapy项目,命名为rosi: scrapy startproject rosi

  可以看到目录里面包含:

 1 rosi/
 2     scrapy.cfg    #项目的配置文件
 3     rosi/            #该项目的Python模块,代码全在这里面
 4         __init__.py
 5         items.py    #放多个model的地方
 6         pipelines.py    #顾名思义 管道,处理items结果的地方
 7         settings.py    #配置文件
 8         spiders/        #爬虫代码
 9             __init__.py
10             ...

  好了。。。说了这么多废话,接下来让我们深入基层!新建rosi项目,然后在rosi/rosi/spiders下面新建rosi_spider.py

import scrapy

class RosiSpider(scrapy.spiders.Spider):
    name = "rosi"    #爬虫名字 唯一
    allowed_domains = ["baidu.com"]    #白名单
    start_urls = ["http://www.baidu.com"]    #爬取起始页面

    def parse(self,response):#回调函数
        print response.url

  上面的代码就是一直简单的爬虫,默认爬取了百度首页。你如果问我,怎么爬取的,什么原理,怎么会爬取了,我只能这么回答你:我表达不出来,因为我也是刚学现在还一团浆糊,我现在只明白怎么用,至于原理,我想等我用的熟了,需要去更深的应用的时候我就会懂了,如果能看的下去可以去看看源码。。。不过我可以引用官方文档中的话来回答你:Scrapy为start_urls属性中的每个url都创建了一个Request对象,并将parse方法最为回调函数(callback)赋值给了Request。Request对象经过调度,执行生成scrapy.http.Response对象并返回给parse方法。

  执行该爬虫:scrapy crawl rosi

  我们既然知道了返回的是response,我们可以试着将里面我们需要的东西匹配读取保存下来,比如文字,比如图片。在Scrapy中呢他拥有自己的Selectors。使用了一种基于XPath和css的机制。深入的东西还是看官方文档:Selector文档 简单介绍介绍几个官方文档的例子:

  • /html/head/title: 选择HTML文档中 <head> 标签内的 <title> 元素
  • /html/head/title/text(): 选择上面提到的 <title> 元素的文字
  • //td: 选择所有的 <td> 元素
  • //div[@class="mine"]: 选择所有具有 class="mine" 属性的 div 元素

  Selector有4个基本方法:

  • xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表 。
  • css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表.
  • extract(): 序列化该节点为unicode字符串并返回list。
  • re(): 根据传入的正则表达式对数据进行提取,返回unicode字符串list列表。

  这里可以自行尝试一下利用XPath取出百度首页的title文字等等等等。

  好了,重点来了。Scrapy中的BaseSpider爬虫类只能抓取start_urls中提供的链接,而利用Scrapy提供的crawlSpider类可以很方便的自动解析网页上符合要求的链接,从而达到爬虫自动抓取的功能。要利用crawSpider和BaseSpider的区别在于crawSpider提供了一组Rule对象列表,这些Rule对象规定了爬虫抓取链接的行为,Rule规定的链接才会被抓取,交给相应的callback函数去处理。

  在rules中通过SmglLinkExtractor提取希望获取的链接。比如:

1 rules = (
2              Rule(SgmlLinkExtractor(allow = (‘detail_\d{4}_\d{5}\.html‘)),callback = ‘parse_image‘,follow=True),
3              )

  这里要解释下,Rule就是一组对象列表,在这里我们设置要过滤的地址。SmglLinkExtractor的主要参数:

  1. allow:满足括号中“正则表达式”的值会被提取,如果为空,则全部匹配。
  2. deny:与这个正则表达式(或正则表达式列表)不匹配的URL一定不提取。
  3. allow_domains:会被提取的链接的domains。
  4. deny_domains:一定不会被提取链接的domains。
  5. restrict_xpaths:使用xpath表达式,和allow共同作用过滤链接。
  6. follow 指定这些通过规则匹配出来的链接是否需要继续,如果callback是None,follow默认为False,否则follow是True。通俗点讲呢就是如果设置为false 那么就访问了这个网站为止不再根据Rule判断该网址,如果设置为True 则继续从该网址里面选择符合Rule的网址出来继续访问。(举个例子:网站有25页,但是首页上提供的页面跳转的标号只有从1-10 后面的隐藏了,平常我们点开10页 页面标号是10-20 如果我们follow为false 我们只能得到1-10页的url 如果设置为True 则每次得到一页都去取标号,我们能得到所有的页码1-25.说的太乱了,一会儿代码中说。)

  我们尝试着从首页得到符合规则的rosi跳转页面:

 1 import scrapy
 2 from scrapy.contrib.spiders import CrawlSpider,Rule
 3 from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
 4 class RosiSpider(CrawlSpider):
 5     name = "rosi"
 6     allowed_domains = ["5442.com"]
 7     start_urls = ["http://www.5442.com/tag/rosi.html"]
 8     rules = (Rule(SgmlLinkExtractor(allow=(‘rosi/[\d]+\.html‘, )),callback=‘parse_href‘,),)
 9     def parse_href(self,response):#注意 回调函数不要命名为parse 否则出bug
10         print response.url

  得到的结果如下:

  天杀的,明明是1-25页好不好,怎么只有这么几个,上面说了如果不设置follow的话默认为false,所以访问了这个就不继续了,我们设置为True就对了。

  我们还是要分析一下这个流程。我们从起始页面:http://www.5442.com/tag/rosi.html 我们需要得到符合条件为tag/rosi/[0-9]+/.html的所有页面,然后访问这些页面得到所有图片集的地址如:http://www.5442.com/meinv/20150904/27062.html和http://www.5442.com/meinv/20150904/27062_2.html,分析可得[0-9_]+\.html。这样我们就得到了所有包含我们需要下载图片url的地址,我们就可以根据XPath得到图片url进行下载。所以我们的爬虫Rule是这样的:

 1 import scrapy,re,urllib2
 2 from scrapy.http import Request
 3 from scrapy.contrib.spiders import CrawlSpider,Rule
 4 from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
 5 from scrapy.selector import Selector
 6 from scrapydemo.items import *
 7
 8 class RosiSpider(CrawlSpider):
 9     name = "rosi"
10     number = 0
11     allowed_domains = ["5442.com"]
12     start_urls = ["http://www.5442.com/tag/rosi.html"]
13     rules = (Rule(SgmlLinkExtractor(allow=(‘rosi/[\d]+\.html‘, )),follow=True),
14             Rule(SgmlLinkExtractor(allow=(‘[0-9_]+\.html‘, )),callback=‘parse_img‘,follow=True)
15         )

  第一条Rule我们得到了rosi的所有页面的信息,在访问这些页面的时候我们并不需要进行处理,所以我们不需要回调函数,然后我们从这些页面信息中提取出了所有的图片集页面,然后我们将图片集页面的返回值response给回调函数进行处理:

 1 def parse_img(self,response):
 2         #print response.url
 3         sel = Selector(response)
 4         src = sel.xpath("//div[@class=‘arcBody‘]//p[@id=‘contents‘]//a//img/@src").extract()
 5         for item in src:
 6             self.saveimg(item)
 7
 8     def saveimg(self,url):
 9         savePath = ‘%d.jpg‘%(self.number)
10         print url
11         self.number += 1
12         try:
13             u = urllib2.urlopen(url)
14             r = u.read()
15             downloadFile = open(savePath,‘wb‘)
16             downloadFile.write(r)
17             u.close()
18             downloadFile.close()
19         except:
20             print savePath,‘can not download.‘

  可能我们要问了,这就完了? items.py 和 pipeline.py咋没用上呢。那就来谈谈这两个:

  Items

  爬取的主要目标就是从非结构性的数据源提取结构性数据,例如网页。 Scrapy提供 Item类来满足这样的需求。Item 对象是种简单的容器,保存了爬取到得数据。 其提供了 类似于词典(dictionary-like) 的API以及用于声明可用字段的简单语法。

1 import scrapy
2
3 class Product(scrapy.Item):
4     name = scrapy.Field()
5     price = scrapy.Field()
6     stock = scrapy.Field()

  他就是一个model,我们可以在回调函数中通过XPath得到内容 然后新建一个Item对象,赋值给他,

1 def parse_href(self,response):
2     items = []
3     item = Product()
4     item["name"] = "xxx"
5     item["price"] = "xxx"
6     items.append(item)
7     return items

  注意,这里我们返回了一个items!!!当Item在Spider中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item的处理。每个item pipeline组件(有时称之为“Item Pipeline”)是实现了简单方法的Python类。他们接收到Item并通过它执行一些行为,同时也决定此Item是否继续通过pipeline,或是被丢弃而不再进行处理。

  以下是item pipeline的一些典型应用:

  • 清理HTML数据
  • 验证爬取的数据(检查item包含某些字段)
  • 查重(并丢弃)
  • 将爬取结果保存到数据库中

  我们可以在pipelines.py中编写自己的itempipeline方法。你必须实现process_item(self,item,spider)方法。更多内容 看官方文档。。。

  让我们来看一下以下这个假设的pipeline,它为那些不含税(price_excludes_vat 属性)的item调整了price 属性,同时丢弃了那些没有价格的item:

 1 from scrapy.exceptions import DropItem
 2
 3 class PricePipeline(object):
 4
 5     vat_factor = 1.15
 6
 7     def process_item(self, item, spider):
 8         if item[‘price‘]:
 9             if item[‘price_excludes_vat‘]:
10                 item[‘price‘] = item[‘price‘] * self.vat_factor
11             return item
12         else:
13             raise DropItem("Missing price in %s" % item)

  以下pipeline将所有(从所有spider中)爬取到的item,存储到一个独立地 items.jl 文件,每行包含一个序列化为JSON格式的item:

 1 import json
 2
 3 class JsonWriterPipeline(object):
 4
 5     def __init__(self):
 6         self.file = open(‘items.jl‘, ‘wb‘)
 7
 8     def process_item(self, item, spider):
 9         line = json.dumps(dict(item)) + "\n"
10         self.file.write(line)
11         return item

  好了,今天就到这儿吧。。。其实我现在也蒙蒙的,接下来就是在实际应用中去提升了,毕竟熟能生巧!!战斗吧 Scrapy!

时间: 2024-10-10 09:53:43

自学Python十二 战斗吧Scrapy!的相关文章

python(十二)上:mysql安装使用详细教程

上节回顾: RabbitMQ几种模式: 平均分发 perfetch =1 durable队列持久化,deliver_mode = 2 消息持久化 一对多广播,exchanage fanout direct topic RPC 一.数据库介绍 1.什么是数据库? 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库, 每个数据库都有一个或多个不同的API用于创建,访问,管理,搜索和复制所保存的数据. 现在我们使用关系型数据库管理系统(RDBMS)来存储和管理的大数据量.所谓的关系型

python(十二)下:ORM框架SQLAlchemy使用学习

此出处:http://blog.csdn.net/fgf00/article/details/52949973 本节内容 ORM介绍 sqlalchemy安装 sqlalchemy基本使用 多外键关联 多对多关系 表结构设计作业  一.ORM介绍 如果写程序用pymysql和程序交互,那是不是要写原生sql语句.如果进行复杂的查询,那sql语句就要进行一点一点拼接,而且不太有重用性,扩展不方便.而且写的sql语句可能不高效,导致程序运行也变慢. 为了避免把sql语句写死在代码里,有没有一种方法直

开班前自学—python基础二_基础数据(2019.02.27)

一 基础数据类型 list: [],各种数据类型的数据,大量的数据,便于操作. tuple: 元组.()只读列表. dic: 存储大量的数据,关系型数据. 二 int str bool相互转换 1 int <---> str int --->str int(str) 条件:str必须全部由数字组成. str --->int str(int) age = int (input('how old are you?')) print(age) # 如果输入内容包括非数字,会报错 s1 =

自学Python之二 Python中的屠龙刀(续)

函数 秉承着一切皆对象的理念,函数作为对象,可以为其赋值新的对象名,也可以作为参数传递给其他函数! 正常的诸如空函数,默认参数等等我们就不提了,在这里着重提一下默认参数里面的坑和lambda函数. 当默认参数为空list时的坑:定义一个函数,传入一个list,添加一个end后返回 1 >>> def func(l=[]): 2 ... l.append('end') 3 ... return l 4 ... 5 >>> 正常调用是没什么问题的: 1 >>&g

【28】Python十二个常用的内建函数

1.abs函数abs(x, /)Return the absolute value of the argument.abs函数返回一个数字的绝对值,也就是去掉数字的正负号的值. >>>print(abs(1)) >>>print(abs(-10)) 作用举例:可以想象一下游戏角色的移动.前进后退,前进表示正,后退表示负.如果不关心方向的正负,那这移动的步数就是绝对值 >>>steps=-2 >>>If abs(steps) >0

孤荷凌寒自学python第六十六天学习mongoDB的基本操作并进行简单封装5

孤荷凌寒自学python第六十六天学习mongoDB的基本操作并进行简单封装5并学习权限设置 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第十二天. 今天继续学习mongoDB的简单操作,并继续对一些可能反复经常使用的操作进行简单的封装.同时通过搜索了解了如何对本地Mongo数据库进行权限设置(没有实践本地数据库的用户权限设置.) 按个人规划,今天是初步了解学习MongoDb数据库的最后一个学习日,后续将在真正使用此数据库时,再对其进行深入研究. 一.今天完成了两个可

孤荷凌寒自学python第八十天开始写Python的第一个爬虫10

(完整学习过程屏幕记录视频地址在文末) 原计划今天应当可以解决读取所有页的目录并转而取出所有新闻的功能,不过由于学习时间不够,只是进一步优化了自定义函数的写法. 一.优化并新增了几个操作word文档的函数 ``` #!/usr/bin/env python3 # -*- coding: utf-8 -*- import string import time import random from docx.enum.style import WD_STYLE_TYPE #所有样式 (包括段落.文字

孤荷凌寒自学python第八十六天对selenium模块进行较详细的了解

(今天由于文中所阐述的原因没有进行屏幕录屏,见谅) 为了能够使用selenium模块进行真正的操作,今天主要大范围搜索资料进行对selenium模块的学习,并且借2019年的新年好运居然在今天就来了,还在学习Python的过程中就接到一个任务,完成了第一个真正有实用价值的作品,大大增强了信心,也对Python爬取内容,操纵网页的能力有了真切的体会. 一.首先真诚感谢以下文章作者的无私分享: 查找到html页面标签对象方法的参考 https://www.cnblogs.com/zhuque/p/8

Python进阶(十二)----re模块

Python进阶(十二)----re模块 一丶re模块 ? re模块是python将正则表达式封装之后的一个模块.正则表达式模式被编译成一系列的字节码,然后由用C编写的匹配引擎执行. #正则表达式: 从一串字符中,找出你想要的字符串. import re ### 单个元字符的匹配 # \W 除了数字 ,字母,中文, 下划线 print(re.findall('\W','dsadas1231 +1-+2*/,.')) # \w 匹配中文,数字,字母,下划线 print(re.findall('\w