python基础 -- 异常处理try的使用及一些思考

成长的道路上,难免会迷茫,难免会不知所措,能做的就是拥有一个不灭的信念,并一路坚持到底。不要丢掉希望,要坚信,明天会更好。



算是自己这周工作的小体会吧。第一天新领了公司配的笔记本,然后配置环境。下午以及第二天都是熟悉公司自己根据Scrapy框架稍作封装的框架,然后一步步调试看程序执行顺序。

第二天下午以及第三天,完成了一个还算简单的爬虫,只是抓取了一个美国的官网。健壮性比较差~~~ 使用xpath抓取时,有些迷茫。原因是网站做的标签有些混乱。或者说是自己经验比较少吧,以后继续补充些这些方面的知识。

第四天一直到现在,一直在写另外一个爬虫。这个的处理就有些麻烦,因为不只是国内的官网,还有美国,以及欧洲一些国家的官网。其他国家的相对好些,一般变化不大,但是国内的额官网一般都会和其他国家的官网差距比较大。对于单品的抓取,使用的类方法,由于国家的不同,需要传递region参数。然后再根据不同情况进行处理~~~

其实这两天在抓取的数据,代码已经有现成的了。但是有时官网会改版,这样就会导致xpath无法选取到目的数据,只能重新修改。

虽然自己水平不高,但是那代码感觉真是没法看啊。稍作修改跑了一下,果然很多数据抓取不到了,然后又细看了一下,好几个地方存在逻辑错误。所以决定重写,按照公司代码比较规范的流程。之前一直在想,代码重要的不就是能正确运行嘛。现在才发现,能运行是程序最基本的东西,其他还有横多重要的部分!

以下只是其中的一个小部分。需要抓取商品的描述(description)。对应的html代码如下:

<!-- 代码比较多  -->
<!-- http://www.hugoboss.com/uk/extra-slim-fit-jacket-%27ryan_cyl%27-in-a-new-wool-blend/hbeu50275029.html?cgid=21600&dwvar_hbeu50275029_color=410_Dark%20Blue  -->
<html>
 <head></head>
 <body>
  <div class="product-tabs tabs"> 
   <h2 class="visually-hidden">Additional Information</h2> 
   <ul class="tabs-menu clearfix"> 
    <li class="active"> 
     <div class="outerContainer"> 
      <div class="innerContainer"> 
       <div class="element">
        <h2><a href="#tab1">Description</a></h2>
       </div> 
      </div> 
     </div> </li> 
    <li> 
     <div class="outerContainer"> 
      <div class="innerContainer"> 
       <div class="element">
        <h2><a href="#tab2">Details</a></h2>
       </div> 
      </div> 
     </div> </li> 
    <li> 
     <div class="outerContainer"> 
      <div class="innerContainer"> 
       <div class="element">
        <h2><a href="#tab3">Material &amp; care</a></h2>
       </div> 
      </div> 
     </div> </li> 
   </ul> 
   <div style="height: 100px;" id="tab1" class="tab-content active"> 
    <a class="print-page button">Print</a> Sophisticated jacket (extra slim-fit) by BOSS made from a new-wool blend in a plain design. This classic, single-breasted business jacket fits perfectly thanks to the 2 side back vents, 2 waist darts at the front and 3 panel seams at the back. The top-quality finish of its design includes decorative stitching and fine felt at 
    <span style="display: inline;" class="showMore">(Show more…)</span> 
    <span style="display: none;" class="fullText"> the undercollar of the notch lapels, and is an exciting item in the Create your Look series. The classic styling of the 2-button jacket, with 1 breast welt pocket and 2 piped pockets with tucked-down flaps, makes simple and more complex style options possible with a variety of suit trousers or waistcoats. In this way, a totally personal look is created that can be adapted to suit different occasions. </span> 
   </div> 
   <div style="height: 100px;" id="tab2" class="tab-content" itemprop="description"> 
    <a class="print-page button">Print</a> Extra slim fit
    <br />New-wool blend with polyamide and elastane
    <br />Plain design
    <br />2-button jacket, 2 side vents 
    <span class="showMore">(Show more…)</span> 
    <span style="display: none;" class="fullText"> <br />Single-breasted<br />Notch lapel with decorative stitching and fine felt on the undercollar<br />1 breast welt pocket, 2 piped pockets with turned down flaps<br />2 waist darts at the front, 3 panel seams at the back<br />4 kissing buttons on the cuff<br />Back length: 72&nbsp;cm in size&nbsp;48<br />Delivered in a HUGO BOSS garment bag </span> 
   </div> 
   <div style="height: 100px;" id="tab3" class="tab-content"> 
    <div class="material-info-text"> 
     <p class="productinfo-text"> Material information: 85% Virgin wool, 11% Polyamid, 4% Elastane, Lining: 52% Acetate, 48% Viscose, Sleeve lining: 51% Viscose, 49% Acetate </p> 
     <p class="productinfo-text"> Do Not Wash, Iron Low Heat, Do Not Bleach, Reduced Dryclean P, Do Not Tumble Dry </p> 
    </div> 
   </div> 
  </div>
 </body>
</html>

这里需要抓取 description 和 details 。算了,直接上代码吧。

@classmethod
def fetch_description(cls, response, region=None, spider=None):
    """
    返回单品描述,不同行之间使用‘\r‘分隔
    由于详细中,存在“打印”以及可能存在的“显示更多”标签。所以将所有文本取出,并替换
    :param response:
    :param spider:
    :return:
    """
    sel = Selector(response)
    description = None
    if region == ‘cn‘:
        description_node = sel.xpath(‘//div[@id="lyr1"][contains(@class,"description")]‘)
    else:
        description_node = sel.xpath(‘//div[contains(@class, "product-detail")]//div[@id="tab1"]‘)
    if description_node:
        try:
            description = ‘\r‘.join(cls.reformat(val) for val in description_node.xpath(‘.//text()‘).extract())
            print_node = description_node.xpath(‘.//*[contains(@class, "print-page")]/text()‘).extract()[0]
            if print_node:
                print_node = cls.reformat(print_node)
                description = description.replace(print_node, ‘‘)
            show_more_node = description_node.xpath(‘.//*[contains(@class, "showMore")]/text()‘).extract()[0]
            if show_more_node:
                show_more_node = cls.reformat(show_more_node)
                description = description.replace(show_more_node, ‘‘)
        except(TypeError, IndexError):
            pass
    description = cls.reformat(description)
    return description

不难看到,其实代码还是挺简单的。只是最开始写代码的时候,考虑不全面,bug到处都是。然后再一步步调试,看自己的代码是否像预期那样执行。

程序大体执行:先判断国家,根据国家的不同,xpath结点的选取有所不同。当结点存在时,继续向下执行,由于xpath.extract() 返回的是一个列表,所以要取值时,需要使用到列表的切片选取第一个元素。但是列表可能为空列表,对空列表执行[0]操作时,会报 IndexError 错误。所以使用 try ... except ...  来捕获异常,此时出现的异常不需要处理,直接向下执行就行。问题的关键就在  try... 下面的代码块中。之前的代码修改了三次,现在才正常。最早的代码如下:

    if description_node:
        try:
            print_node = description_node.xpath(‘.//*[contains(@class, "print-page")]/text()‘).extract()[0]
            show_more_node = description_node.xpath(‘.//*[contains(@class, "showMore")]/text()‘).extract()[0]
            description = ‘\r‘.join(cls.reformat(val) for val in description_node.xpath(‘.//text()‘).extract())
            if print_node:
                print_node = cls.reformat(print_node)
                description = description.replace(print_node, ‘‘)
            if show_more_node:
                show_more_node = cls.reformat(show_more_node)
                description = description.replace(show_more_node, ‘‘)
        except(TypeError, IndexError):
            pass

不难发现,这段代码存在严重的问题。当执行到 try 代码块中,说明存在 描述结点的。

但此时,如果 print_node 或 show_more_node 的xpath 返回空值时,他们就是空列表,程序便终止执行 try 中剩下的代码,直接进入 except 异常处理块中。修改完如下:

    if description_node:
        try:
            description = ‘\r‘.join(cls.reformat(val) for val in description_node.xpath(‘.//text()‘).extract())
            print_node = description_node.xpath(‘.//*[contains(@class, "print-page")]/text()‘).extract()[0]
            show_more_node = description_node.xpath(‘.//*[contains(@class, "showMore")]/text()‘).extract()[0]
            if print_node:
                print_node = cls.reformat(print_node)
                description = description.replace(print_node, ‘‘)
            if show_more_node:
                show_more_node = cls.reformat(show_more_node)
                description = description.replace(show_more_node, ‘‘)
        except(TypeError, IndexError):
            pass

此时如果html中存在 description,就一定能抓取到。但是代码中存在 ‘打印’和 可能存在 ‘显示更多’。通过执行发现‘打印’二字,时而出现时而消失。当时感觉挺奇怪的,然后又一想,可能是html代码有些变化,导致xpath提取不出来 print_node 。但是使用 scrapt shell url ,调试时发现可以取到 ‘打印’的。然后又单步调试,发现,执行到 show_more_node 后,直接就进入了 except 代码段。恍然明白,这段描述没有‘显示更多’,剩下的替换代码,没有执行。然后又修改代码:

    if description_node:
        try:
            description = ‘\r‘.join(cls.reformat(val) for val in description_node.xpath(‘.//text()‘).extract())
            print_node = description_node.xpath(‘.//*[contains(@class, "print-page")]/text()‘).extract()[0]
            if print_node:
                print_node = cls.reformat(print_node)
                description = description.replace(print_node, ‘‘)
            show_more_node = description_node.xpath(‘.//*[contains(@class, "showMore")]/text()‘).extract()[0]
            if show_more_node:
                show_more_node = cls.reformat(show_more_node)
                description = description.replace(show_more_node, ‘‘)
        except(TypeError, IndexError):
            pass

此时代码完全正常了。

还需要注意的一点就是 try 中代码的顺序。因为这段最主要的目的就是抓取 description ,如果存在的话, ‘打印’结点可能存在,‘显示更多’也可能存在,但是‘打印’一定出现在‘显示更多’前面,所以顺序需要时:  description -> print_node -> show_more_node

当然这也跟代码的书写有些关系。如果使用  if 来判断抓取返回的列表是否为空,就不用再使用 try 异常处理了。



像是个寓言小故事,最后的结论就是:

# 在使用
try:
    pass
    # 一定要注意这里面语句的顺序
    # 一旦出现异常,代码就会终止执行本块剩下的代码
except:
    pass

# 所以 try 的使用,一定要谨慎
# ‘知道’ --》 ‘体会到’ 还是有一点距离的

一直在纠结,是谨慎使用,还是使用谨慎。好像都对,又好像都不太确切~ 哈哈~~~

时间: 2024-08-24 23:45:22

python基础 -- 异常处理try的使用及一些思考的相关文章

python基础-异常处理

1.什么是异常 异常可以理解为一个对不正常事情的处理机制 一般情况下,在python中无法正常处理程序时就会发生一个异常 异常处理可以让错误变得更人性化 2.异常处理 捕捉异常可以使用try/except语句 try/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理 如果不想在异常发生时结束你的程序,只需在try里捕获它 语法: try: <语句> #运行别的代码 except <名字>: <语句> #如果在try部分引发了'nam

python 基础---异常处理

程序一旦发生错误,就从错误的位置停下来了,不在继续执行后面的内容使用try和except就能处理异常 1 try: 2 被检测的代码块 3 except 异常类型: 4 try中一旦检测到异常,就执行这个位置的逻辑 try我们需要处理的代码 except 后面跟一个错误类型 当代码发生错误且错误类型符合的时候 就会执行except中的代码 支持多分支 Exception 万能的处理机制 有了万能的处理机制仍然需要把能预测到的问题单独处理 单独处理的所有内容都应该写在万能异常之前 else 没有异

python基础 异常处理 try except

异常处理 某些时候我们能够预判程序可能会出现何种类型的错误,而此时我们希望程序继续执行而不是退出,此时就需要用到异常处理:下面是常用的几种异常处理方法 1 #通过实例属性 列表 字典构造对应的异常 2 class Human(object): 3 def __init__(self, name, age, sex): 4 self.name = name 5 self.age = age 6 def get_info(self): 7 print("my name is %s,age is %s

Python基础 —— 目录

Python基础 Python基础 -- 基本数据类型 Python基础 -- 基本数据类型的方法总结 Python基础 -- 比较运算符 + 逻辑运算符 Python基础 -- 异常处理 Python基础 -- 常用模块 Python基础 -- 模块和包 Python基础 -- PIL模块 Python基础 -- 装饰器函数 Python基础 -- 内置函数 Python基础 -- range()/xrange() 面向对象 -- 特殊且重要的双下方法 面向对象 -- 类的成员.成员修饰符.特

Python 基础之 异常处理

python 基础之异常处理 说到异常处理,就得先问一下,什么是异常处理?  先来看一下,什么是异常? 异常就是:程序运行时发出的错误的信号. 异常的种类先来看一下: 一.常见的异常 AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x IOError 输入/输出异常:基本上是无法打开文件 ImportError 无法引入模块或包:基本上是路径问题或名称错误 IndentationError 语法错误(的子类) :代码没有正确对齐 IndexError

Python自动化 【第七篇】:Python基础-面向对象高级语法、异常处理、Scoket开发基础

本节内容: 1.     面向对象高级语法部分 1.1   静态方法.类方法.属性方法 1.2   类的特殊方法 1.3   反射 2.     异常处理 3.     Socket开发基础 1.     面向对象高级语法部分 1.1   静态方法.类方法.属性方法 1)   静态方法 通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法.普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访

Python 基础 - Day 4 Learning Note - Generator 生成器

列表生成器/列表解析 list comprehension 简单灵活地创建列表,通常和lambda(), map(), filter() 一起使用 通过列表生成式, 直接创建列表.但是,收到内容限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问几个元素,那其他的就白占空间.列表生成器能够一边循环一边计算,大大节省大量的空间.是生成器的一种. 只有调用,才能生成. 不支持切片操作,只能通过__next()___一个个取数字. 基本语法

Python基础教程【读书笔记】 - 2016/7/5

希望通过博客园持续的更新,分享和记录Python基础知识到高级应用的点点滴滴! 第三波:第8章  异常 [总览]学习如何创建和引发自定义的异常,以及处理异常的各种方法. 为了能够处理异常事件,可以再所有可能发生这类事件的地方都使用条件语句,但是这么做可能不仅会没效率和不灵活,而且还会让程序难以阅读.Python的异常对象提供了非常强大的替代解决方案. [8.1] 什么是异常 Python用异常对象(exception object)来表示异常情况.遇到错误后,会引发异常.如果异常对象并未被处理或

python基础学习08(核心编程第二版)部分

# -*- coding: utf-8 -*- # ==================== #File: python #Author: python #Date: 2014 #==================== __author__ = 'Administrator' #异常 """ NameError: 尝试访问一个未申明的变量 ZeroDivisionError:  除数为零 SyntaxError: 解释器语法错误 IndexError: 请求的索引超出序列范