Python练习

一、知识点

知识点1:Iterable和Iterator

|-------------------|-------------------------------------------|------------------------------------------|
| | 可迭代对象 Iterable | 迭代器 Iterator |
| 定义 | 可以一次返回其成员的对象,这意味着这些对象可以通过for...in循环进行遍历 | 是表示数据流的对象,通过重复调用迭代器的*next()*方法返回数据流中的连续项 |
| 核心方法 | iter() | iter()和__next__() |
| 获取方式 | 直接使用可迭代对象本身 | 通过对可迭代对象调用 iter()__iter__() 获得 |
| 状态 | 通常不保存迭代状态 | 保存当前的迭代状态(位置) |
| 遍历 | 不能直接使用 next() 遍历 | 可以使用 next() 逐个获取元素 |
| 遍历次数 | 可被多次遍历(每次创建新的迭代器) | 通常只能遍历一次(消耗型) |
| 示例类型 | 列表、元组、字符串、字典、集合 | iter(list) 返回的对象、生成器对象 |
| StopIteration | 不会直接引发 | 当元素耗尽时引发 StopIteration 异常 |

知识点2:map()和reduce()

python 复制代码
map() 函数:
1. 两个参数: function and Iterable
2. 作用: 将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回
3. 示例1: f(x)=x**2, 把f(x)作用到list[1,2,3,4,5,6,7,8,9],代码如下:
>>> def f(x):
        return x*x
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]
4、示例2:把list[1,2,3,4,5,6,7,8,9]转换为字符串,代码如下:
>>> list(map(str,[1, 2, 3, 4, 5, 6, 7, 8, 9]))
['1', '2', '3', '4', '5', '6', '7', '8', '9']
python 复制代码
reduce()函数:
1、两个参数:function和iterable
2、作用:reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
3、示例1:对一个序列求和
>>> from functools import reduce
>>> def add(x, y):
        return x + y
>>> reduce(add, [1, 3, 5, 7])
16
4、str转换为int
>>> from functools import reduce
>>> def f(x, y):
        return x*10+y
>>> def strToInt(s):
        num = {'0':0, '1':1, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9}
        return num[s]
>>> reduce(f,map(strToInt,'1357'))
1357

相关练习:

1、利用map()函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。输入:['adam', 'LISA', 'barT'],输出:['Adam', 'Lisa', 'Bart']

python 复制代码
def f(name):
    return name[0].upper() + name[1:].lower()
print(list(map(f,['adam','LISA','barT'])))

2、请编写一个prod()函数,可以接受一个list并利用reduce()求积:

python 复制代码
from functools import reduce

def prod(x, y):
    return x * y

print('3 * 5 * 7 * 9 =', reduce(prod,[3, 5, 7, 9]))
if reduce(prod,[3, 5, 7, 9]) == 945:
    print('测试成功!')
else:
    print('测试失败!')

3、利用mapreduce编写一个str2float函数,把字符串'123.456'转换成浮点数123.456

python 复制代码
from functools import reduce
def strToInt(s):
    num = {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}
    return num[s]

def f(x,y):
    return x*10+y

def str2float(s):
    return reduce(f,map(strToInt,s.split('.')[0]))+reduce(f,map(strToInt,s.split('.')[1]))/10**len(s.split('.')[1])

print('str2float(\'123.456\') =', str2float('123.456'))
if abs(str2float('123.456') - 123.456) < 0.00001:
    print('测试成功!')
else:
    print('测试失败!')

知识点3:filter()

python 复制代码
filter()函数:
1、两个参数:函数和序列
2、作用:过滤
3、示例:保留奇数
>>> def is_odd(n):
        return n % 2 == 1
>>> list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
[1, 5, 9, 15]

相关练习:

1、回数是指从左向右读和从右向左读都是一样的数,例如12321909。请利用filter()筛选出回数:

python 复制代码
def is_palindrome(n):
    s = str(n)
    return s == s[::-1]

# 测试:
output = filter(is_palindrome, range(1, 1000))
print('1~1000:', list(output))

知识点4:闭包

使用闭包,就是内层函数引用了外层函数的局部变量。如果只是读外层变量的值,我们会发现返回的闭包函数调用一切正常;但如果是对其赋值,则会把x当做函数counter()的局部变量

python 复制代码
def createCounter():
    x = 0
    def counter():
        nonlocal x
        x = x + 1
        return x
    return counter

# 测试:
counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5

知识点5:slots

通过__slots__来限制实例能添加的属性。

python 复制代码
class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称

s = Student() # 创建新的实例
s.name = 'Michael' # 绑定属性'name'
s.age = 25 # 绑定属性'age'
s.score = 99 # 绑定属性'score'    #报错:AttributeError: 'Student' object has no attribute 'score'

slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。除非在子类中也定义__slots,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__。

python 复制代码
class Stu2(Stu):
    pass

ss=Stu2()
ss.name='bbb'
ss.age=21
ss.score=98
print(ss.score)    #输出:98

class Stu3(Stu):
    __slots__ = ('name','gender')

sss=Stu3()
sss.name='ccc'
sss.gender='m'
sss.age=20
print(sss.name)    #输出:ccc
print(sss.gender)    #输出:m
print(sss.age)    #输出:20

知识点6:@property

@property装饰器就是负责把一个方法变成属性调用的。

python 复制代码
class Screen(object):
    @property
    def width(self):
        return self.width
    @width.setter    #负责把该方法变成属性赋值
    def width(self, value):
        self._width = value
    @property
    def height(self):
        return self.height
    @height.setter
    def height(self, value):
        self._height = value

    @property    #只读属性,只定义getter方法,不定义setter方法就是一个只读属性
    def resolution(self):
        return self._width * self._height

# 测试:
s = Screen()
s.width = 1024
s.height = 768
print('resolution =', s.resolution)

知识点7:调试

错误信息:https://docs.python.org/3/library/exceptions.html#exception-hierarchy

1、print():把可能有问题的变量打印出来。

2、断言(assert):如果断言失败,assert语句本身就会抛出异常。(可通过-O参数关闭assert,如:python -O err.py)。

python 复制代码
def foo(s):
    n = int(s)
    assert n != 0, 'n is zero!'    #表达式n!=0应该是True,否则,后面代码出错。
    return 10 / n

def main():
    foo('0')

3、logging:和assert相比,logging不会抛出错误,而且可以输出到文件中。logging允许你指定记录信息的级别,有debug、info、warning、error等几个级别,当我们指定level=INFO时,其他级别的信息就不起作用了。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。另一个好处就是可以通过简单的配置,一条语句同时输出到不同的地方,如console和文件。

python 复制代码
import logging
logging.basicConfig(level=logging.INFO)

4、调试器pdb:让程序单步运行,可随时查看运行状态。

以参数 -m pdb 启动后,pdb定位到下一步要执行的代码;输入命令 l 查看代码;输入命令 n 单步执行代码;任何时候都可以输入命令 p 变量名 来查看变量;输入命令 q 结束调试,退出程序。

pdb.set_trace() #在可能出错的地方放一个,就可以设置一个断点,运行代码时,程序会自动在该语句暂停并进入pdb调试环境,可以使用命令p 来查看变量,或用命令 c 继续运行。

5、IDE:支持调试的IDE

知识点8:单元测试

对一个模块、一个函数或者一个类来进行正确性检验的测试工作。

编写单元测试时,我们需要编写一个测试类,从unittest.TestCase继承。

test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行。

对每一类测试都需要编写一个test_xxx()方法。由于unittest.TestCase提供了很多内置的条件判断,我们只需要调用这些方法就可以断言输出是否是我们所期望的。

python 复制代码
import unittest

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def get_grade(self):
        if self.score >= 60 and self.score < 80:
            return 'B'
        elif self.score >= 80 and self.score <= 100:
            return 'A'
        elif self.score < 0 or self.score > 100:
            raise ValueError
        return 'C'
class TestStudent(unittest.TestCase):

    def test_80_to_100(self):
        s1 = Student('Bart', 80)
        s2 = Student('Lisa', 100)
        self.assertEqual(s1.get_grade(), 'A')
        self.assertEqual(s2.get_grade(), 'A')

    def test_60_to_80(self):
        s1 = Student('Bart', 60)
        s2 = Student('Lisa', 79)
        self.assertEqual(s1.get_grade(), 'B')
        self.assertEqual(s2.get_grade(), 'B')

    def test_0_to_60(self):
        s1 = Student('Bart', 0)
        s2 = Student('Lisa', 59)
        self.assertEqual(s1.get_grade(), 'C')
        self.assertEqual(s2.get_grade(), 'C')

    def test_invalid(self):
        s1 = Student('Bart', -1)
        s2 = Student('Lisa', 101)
        with self.assertRaises(ValueError):
            s1.get_grade()
        with self.assertRaises(ValueError):
            s2.get_grade()

if __name__ == '__main__':
    unittest.main()

知识点9:正则表达式

在正则表达式中,如果直接给出字符,就是精确匹配。

search()方法用于在字符串中搜索正则表达式模式第一次出现的位置。

第一个参数是正则表达式模式,也就是你要描述的搜索规则。

找到后返回的范围是以下标0开始的。

python 复制代码
import re
re.search(r"Fish","I Love Fish!") 
<re.Match object; span=(7, 11), match='Fish'>

\d可以匹配一个数字

python 复制代码
>>> re.search(r'\d', 'I love 123 FishC.com!')
<re.Match object; span=(7, 8), match='1'>

\w可以匹配一个字母或数字

.可以匹配任意字符

python 复制代码
>>> re.search(r'.', 'I love FishC.com!')
<re.Match object; span=(0, 1), match='I'>
>>> re.search(r'co.', 'I love FishC.com!')
<re.Match object; span=(13, 16), match='com'>

反斜杠剥夺元字符(.)的特殊能力。

python 复制代码
>>> re.search(r'\.', 'I love FishC.com!')
<re.Match object; span=(12, 13), match='.'>

*表示任意个字符(包括0个)

+表示至少一个字符

?表示0个或1个字符

{n}表示n个字符

{n,m}表示n-m个字符:

  • '00\d'可以匹配'007',但无法匹配'00A'
  • '\d\d\d'可以匹配'010'
  • '\w\w\d'可以匹配'py3'
  • 'py.'可以匹配'pyc''pyo''py!'等等
  • eg:\d{3}\s+\d{3,8}
  1. \d{3}表示匹配3个数字,例如'010'
  2. \s可以匹配一个空格(也包括Tab等空白符),所以\s+表示至少有一个空格;
  3. \d{3,8}表示3-8个数字,例如'1234567'

要做更精确地匹配,可以用[]表示范围,比如:

0-9a-zA-Z\\_可以匹配一个数字、字母或者下划线;

0-9a-zA-Z\\_+可以匹配至少由一个数字、字母或者下划线组成的字符串,比如'a100','0_Z','Py3000'等等;

a-zA-Z\\_0-9a-zA-Z\\_*可以匹配由字母或下划线开头,后接任意个由一个数字、字母或者下划线组成的字符串,也就是Python合法的变量;

a-zA-Z\\_0-9a-zA-Z\\_{0, 19}更精确地限制了变量的长度是1-20个字符(前面1个字符+后面最多19个字符)。

A|B可以匹配A或B,所以(P|p)ython可以匹配'Python'或者'python'。

^表示行的开头,^\d表示必须以数字开头。

表示行的结束,\\d表示必须以数字结束。

使用 将任何内容包起来就是一个字符类,它的含义是你只要匹配这个字符类中的任何字符,结果就算作匹配。默认区分大小写。

python 复制代码
>>> re.search(r'[aeiou]', 'I love 123 FishC.com!')
<re.Match object; span=(3, 4), match='o'>

>>> re.search(r'[aeiouAEIOU]', 'I love 123 FishC.com!')
<re.Match object; span=(0, 1), match='I'>
>>> re.search(r'[a-z]', 'I love 123 FishC.com!')
<re.Match object; span=(2, 3), match='l'>
>>> re.search(r'[0-2][0-5][0-5]', 'I love 123 FishC.com!')
<re.Match object; span=(7, 10), match='123'>

# 重复匹配
>>> re.search(r'ab{3}c', 'abbbc')
<re.Match object; span=(0, 5), match='abbbc'>

# 超过3个或者少于3个都不能匹配
>>> re.search(r'ab{3,5}c', 'abbbc')
<re.Match object; span=(0, 5), match='abbbc'>
>>> re.search(r'ab{3,5}c', 'abbbbc')
<re.Match object; span=(0, 6), match='abbbbc'>
>>> re.search(r'ab{3,5}c', 'abbbbbc')
<re.Match object; span=(0, 7), match='abbbbbc'>

用法:

正则表达式所有的元字符 . ^ $ * + ? {} \[\] \ | ()

符号 含义
. 表示匹配除了换行符外的任何字符。注:通过设置 re.DOTALL 标志可以使 . 匹配任何字符(包含换行符)
| A | B,表示匹配正则表达式 A 或者 B
^ (脱字符)匹配输入字符串的开始位置。如果设置了 re.MULTILINE 标志,^ 也匹配换行符之后的位置
$ 匹配输入字符串的结束位置。如果设置了 re.MULTILINE 标志,$ 也匹配换行符之前的位置
\ 将一个普通字符变成特殊字符,例如 \d 表示匹配所有十进制数字。 解除元字符的特殊功能,例如 . 表示匹配点号本身。引用序号对应的子组所匹配的字符串
... 字符类,匹配所包含的任意一个字符。注:连字符 - 如果出现在字符串中间表示字符范围描述;如果出现在首位则仅作为普通字符。特殊字符仅有反斜线 \ 保持特殊含义,用于转义字符。其它特殊字符如 *、+、? 等均作为普通字符匹配。脱字符 ^ 如果出现在首位则表示匹配不包含其中的任意字符;如果 ^ 出现在字符串中间就仅作为普通字符匹配
{M,N} M 和 N 均为非负整数,其中 M <= N,表示前边的 RE 匹配 M ~ N 次。注:{M,} 表示至少匹配 M 次;{,N} 等价于 {0,N};{N} 表示需要匹配 N 次
* 匹配前面的子表达式零次或多次,等价于 {0,}
+ 匹配前面的子表达式一次或多次,等价于 {1,}
? 匹配前面的子表达式零次或一次,等价于 {0,1}
*?, +?, ?? 默认情况下 、+ 和 ? 的匹配模式是贪婪模式(即会尽可能多地匹配符合规则的字符串);?、+? 和 ?? 表示启用对应的非贪婪模式。举个例子:对于字符串 "FishCCC",正则表达式 FishC+ 会匹配整个字符串,而 FishC+? 则匹配 "FishC"
{M,N}? 同上,启用非贪婪模式,即只匹配 M 次
(...) 匹配圆括号中的正则表达式,或者指定一个子组的开始和结束位置。注:子组的内容可以在匹配之后被 \数字 再次引用 。举个例子:(\w+) \1 可以字符串 "FishC FishC.com" 中的 "FishC FishC"(注意有空格)
(?...) (? 开头的表示为正则表达式的扩展语法(下边这些是 Python 支持的所有扩展语法)
(?aiLmsux) 1. (? 后可以紧跟着 'a','i','L','m','s','u','x' 中的一个或多个字符,只能在正则表达式的开头使用。2. 每一个字符对应一种匹配标志:re-A(只匹配 ASCII 字符),re-I(忽略大小写),re-L(区域设置),re-M(多行模式), re-S(. 匹配任何符号),re-X(详细表达式),包含这些字符将会影响整个正则表达式的规则。3. 当你不想通过 re.compile() 设置正则表达式标志,这种方法就非常有用啦。注意,由于 (?x) 决定正则表达式如何被解析,所以它应该总是被放在最前边(最多允许前边有空白符)。如果 (?x) 的前边是非空白字符,那么 (?x) 就发挥不了作用了
(?:...) 非捕获组,即该子组匹配的字符串无法从后边获取
(?P<name>...) 命名组,通过组的名字(name)即可访问到子组匹配的字符串
(?P=name) 反向引用一个命名组,它匹配指定命名组匹配的任何内容
(?#...) 注释,括号中的内容将被忽略
(?=...) 前向肯定断言。如果当前包含的正则表达式(这里以 ... 表示)在当前位置成功匹配,则代表成功,否则失败。一旦该部分正则表达式被匹配引擎尝试过,就不会继续进行匹配了;剩下的模式在此断言开始的地方继续尝试。举个例子:love(?=FishC) 只匹配后边紧跟着 "FishC" 的字符串 "love"
(?!...) 前向否定断言。这跟前向肯定断言相反(不匹配则表示成功,匹配表示失败)。举个例子:FishC(?!.com) 只匹配后边不是 ".com" 的字符串 "FishC"
(?<=...) 后向肯定断言。跟前向肯定断言一样,只是方向相反。举个例子:(?<=love)FishC 只匹配前边紧跟着 "love" 的字符串 "FishC"
(?<!...) 后向否定断言。跟前向肯定断言一样,只是方向相反。举个例子:(?<!FishC).com 只匹配前边不是 "FishC" 的字符串 ".com"
(?(id/name)yes-pattern|no-pattern) 1. 如果子组的序号或名字存在的话,则尝试 yes-pattern 匹配模式;否则尝试 no-pattern 匹配模式。2. no-pattern 是可选的。举个例子:(<)?(\w+@\w+(?:.\w+)+)(?(1)>|$) 是一个匹配邮件格式的正则表达式,可以匹配 user@fishc.com 和 'user@fishc.com',但是不会匹配 '<user@fishc.com' 或 'user@fishc.com>'
\ 下边列举了由字符 '' 和另一个字符组成的特殊含义。注意,'' + 元字符的组合可以解除元字符的特殊功能
\序号 1. 引用序号对应的子组所匹配的字符串,子组的序号从 1 开始计算。2. 如果序号是以 0 开头,或者 3 个数字的长度。那么不会被用于引用对应的子组,而是用于匹配八进制数字所表示的 ASCII 码值对应的字符。举个例子:(.+) \1 会匹配 "FishC FishC" 或 "55 55",但不会匹配 "FishCFishC"(注意,因为子组后边还有一个空格)
\A 匹配输入字符串的开始位置
\Z 匹配输入字符串的结束位置
\b 匹配一个单词边界,单词被定义为 Unidcode 的字母数字或下横线字符。举个例子:\bFishC\b 会匹配字符串 "love FishC"、FishC." 或 "(FishC)"
\B 匹配非单词边界,其实就是与 \b 相反。举个例子:py\B 会匹配字符串 "python"、"py3" 或 "py2",但不会匹配 "py "、"py." 或 "py!"
\d 1. 对于 Unicode(str 类型)模式:匹配任何一个数字,包括 0-9 和其他数字字符;如果开启了 re.ASCII 标志,就只匹配 0-9。2. 对于 8 位(bytes 类型)模式:匹配 0-9 中任何一个数字
\D 匹配任何非 Unicode 的数字,其实就是与 \d 相反;如果开启了 re.ASCII 标志,则相当于匹配 \^0-9
\s 1. 对于 Unicode(str 类型)模式:匹配 Unicode 中的空白字符(包括 \\t\\n\\r\\f\\v 以及其他空白字符);如果开启了 re.ASCII 标志,就只匹配 \\t\\n\\r\\f\\v。2. 对于 8 位(bytes 类型)模式:匹配 ASCII 中定义的空白字符,即 \\t\\n\\r\\f\\v
\S 匹配任何非 Unicode 中的空白字符,其实就是与 \s 相反;如果开启了 re.ASCII 标志,则相当于匹配 \^ \\t\\n\\r\\f\\v
\w 1. 对于 Unicode(str 类型)模式:匹配任何 Unicode 的单词字符,基本上所有语言的字符都可以匹配,当然也包括数字和下横线;如果开启了 re.ASCII 标志,就只匹配 a-zA-Z0-9_。2. 对于 8 位(bytes 类型)模式:匹配 ASCII 中定义的字母数字,即 a-zA-Z0-9_
\W 匹配任何非 Unicode 的单词字符,其实就是与 \w 相反;如果开启了 re.ASCII 标志,则相当于 \^a-zA-Z0-9_
转义符号 正则表达式还支持大部分 Python 字符串的转义符号:\a,\b,\f,\n,\r,\t,\u,\U,\v,\x,\\。注:\b 通常用于匹配一个单词边界,只有在字符类中才表示"退格";\u 和 \U 只有在 Unicode 模式下才会被识别;八进制转义(\数字)是有限制的,如果第一个数字是 0,或者如果有 3 个八进制数字,那么就被认为是八进制数;其他情况则被认为是子组引用;至于字符串,八进制转义总是最多只能是 3 个数字的长度

二、练习

练习1

请修改列表生成式,通过添加if语句保证列表生成式能正确地执行:

python 复制代码
L1 = ['Hello', 'World', 18, 'Apple', None]
L2 = [i.lower() for i in L1 if isinstance(i,str)]

# 测试:
print(L2)
if L2 == ['hello', 'world', 'apple']:
    print('测试通过!')
else:
    print('测试失败!')

练习2

杨辉三角定义如下:

复制代码
          1
         / \
        1   1
       / \ / \
      1   2   1
     / \ / \ / \
    1   3   3   1
   / \ / \ / \ / \
  1   4   6   4   1
 / \ / \ / \ / \ / \
1   5   10  10  5   1

把每一行看做一个list,试写一个generator,不断输出下一行的list:

python 复制代码
def triangles():
    t=[1]
    while True:
        yield t
        t=[t[i-1]+t[i] if i>0 else t[i] for i in range(len(t))]+[1]
    pass

# 期待输出:
# [1]
# [1, 1]
# [1, 2, 1]
# [1, 3, 3, 1]
# [1, 4, 6, 4, 1]
# [1, 5, 10, 10, 5, 1]
# [1, 6, 15, 20, 15, 6, 1]
# [1, 7, 21, 35, 35, 21, 7, 1]
# [1, 8, 28, 56, 70, 56, 28, 8, 1]
# [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
n = 0
results = []
for t in triangles():
    results.append(t)
    n = n + 1
    if n == 10:
        break

for t in results:
    print(t)

if results == [
    [1],
    [1, 1],
    [1, 2, 1],
    [1, 3, 3, 1],
    [1, 4, 6, 4, 1],
    [1, 5, 10, 10, 5, 1],
    [1, 6, 15, 20, 15, 6, 1],
    [1, 7, 21, 35, 35, 21, 7, 1],
    [1, 8, 28, 56, 70, 56, 28, 8, 1],
    [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
]:
    print('测试通过!')
else:
    print('测试失败!')

练习3

Studentgender属性改造为枚举类型

python 复制代码
from enum import Enum, unique

@unique
class Gender(Enum):
    Male = 0
    Female = 1

class Student(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

# 测试:
bart = Student('Bart', Gender(0))
if bart.gender == Gender.Male:
    print('测试通过!')
else:
    print('测试失败!')

三、实践

1、下载一张图像

urllib.request用于打开和读取URL

python 复制代码
import urllib.request

rep = urllib.request.urlopen("http://placecats.com/louie/300/300")
cat_img = rep.read()

with open('D:\Desktop\cat_300_300.jpg','wb') as f:
    f.write(cat_img)

2、用有道来翻译文本

urllib.parse用于解析URL

所有来自URL解析函数的返回值都会提供encode()方法和decode()方法。

python 复制代码
import urllib.request
import urllib.parse
import json

content = input("请输入需要翻译的内容:")
url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=http://www.youdao.com"
data = {}
data['type'] = 'AUTO'
data['i'] = content
data['doctype'] = 'json'
data['version'] = '2.1'
data['keyfrom'] = 'fanyi.web'
data['ue'] = 'UTF-8'
data['typoResult'] = 'true'
data = urllib.parse.urlencode(data).encode('utf-8')  # 转换格式并编码为utf-8
response = urllib.request.urlopen(url, data)  # post请求必须带上data参数
html = response.read().decode('utf-8')
target = json.loads(html)
print("翻译结果:%s" % (target['translateResult'][0][0]['tgt']))  # 一层一层剥掉

设置headers参数有两种方法:

  • 实例化Request参数时将headers参数传进去
python 复制代码
import urllib.request
import urllib.parse
import json

content = input("请输入需要翻译的内容:")
url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=http://www.youdao.com"
head = {}
head['Referer'] = 'http://fanyi.youdao.com/'
head['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'

data = {}
data['type'] = 'AUTO'
data['i'] = content
data['doctype'] = 'json'
data['version'] = '2.1'
data['keyfrom'] = 'fanyi.web'
data['ue'] = 'UTF-8'
data['typoResult'] = 'true'

data = urllib.parse.urlencode(data).encode('utf-8')
req = urllib.request.Request(url, data, headers=head)
response = urllib.request.urlopen(req)
html = response.read().decode('utf-8')
target = json.loads(html)
print("翻译结果:%s" % (target['translateResult'][0][0]['tgt']))
print(req.headers)
  • 通过add_header()方法往Request对象添加headers
python 复制代码
import urllib.request
import urllib.parse
import json

content = input("请输入需要翻译的内容:")
url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=http://www.youdao.com"
data = {}
data['type'] = 'AUTO'
data['i'] = content
data['doctype'] = 'json'
data['version'] = '2.1'
data['keyfrom'] = 'fanyi.web'
data['ue'] = 'UTF-8'
data['typoResult'] = 'true'

data = urllib.parse.urlencode(data).encode('utf-8')
req = urllib.request.Request(url, data)
req.add_header('Referer', 'http://fanyi.youdao.com')
req.add_header('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36')
response = urllib.request.urlopen(req)
html = response.read().decode('utf-8')
target = json.loads(html)
print("翻译结果:%s" % (target['translateResult'][0][0]['tgt']))
print(req.headers)

如果同一IP在短时间内对服务器频繁访问,一旦超过服务器设置的访问频率,就会返回一个验证码页面,爬虫就不能正常获取信息,所以被拒绝,可通过以下两种方法解决:

  • 延迟提交的时间
  • 使用代理

3、

相关推荐
许彰午5 小时前
14_Java泛型完全指南
java·windows·python
广州灵眸科技有限公司6 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) Easy-Eai编译环境准备与更新
服务器·前端·人工智能·python·深度学习
TechWayfarer6 小时前
IP风险等级评估接入实战:金融信贷如何用IP画像辅助风控审核
python·tcp/ip·安全·金融
Esaka_Forever6 小时前
uv init 完整用法(Python 最快包管理器)
服务器·python·uv
代码中介商8 小时前
C++左值与右值:核心判断法则详解
开发语言·c++
JAVA9658 小时前
JAVA面试-并发篇 05-并发包AQS队列实现原理是什么
java·开发语言·面试
Halo_tjn9 小时前
反射与设计模式1
java·开发语言·算法
神仙别闹9 小时前
基于Python + SQL server 实现(GUI)原神圣遗物管理与角色数值模拟系统
java·数据库·python
珊瑚里的鱼9 小时前
手撕单例模式中的饿汉模式和懒汉模式,懒汉模式还要再多加一个C++11版本的
开发语言·c++·单例模式
是有头发的程序猿9 小时前
电商自动化实战:淘宝/天猫item_get商品详情API全量采集教程(Python源码)
java·python·自动化