2py72py字段表示的含义义

由于Python源代码也是一个文本文件所以,当你的源代码中包含中文的时候在保存源代码时,就需要务必指定保存为UTF-8编码Python解释器读取源代码时,为了让它按UTF-8编码读取峩们通常在文件开头写上这两行:

第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序Windows系统会忽略这个注释;

第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码否则,你在源代码中写的中文输出可能会有乱码

申明了UTF-8编码并不意味着你的.py文件就是UTF-8编码的,必须并且要确保文本编辑器正在使用UTF-8 without BOM编码
如果.py文件本身使用UTF-8编码并且也申明了# -*- coding: utf-8 -*-,打开命令提示符测试就可以正常显示中文

Python的语法采用缩进方式使用4個空格的缩进。
Python程序是大小写敏感的

在Windows上是不能像.exe文件那样直接运行.py文件的但是,在Mac和Linux上是可以的方法是在.py文件的第一荇加上一个特殊的注释:


 


 
输出格式print()也可以接受多个字符串,用逗号“,”隔开就可以连成一串输出,遇到逗号“,”会输出一个空格

 
输出格式化的 类似’亲爱的xxx你好!’之类的字符串而xxx的内容都是根据变量变化的,%运算符就是用来格式化字符串的

 
写入格式input(),将输入数据赋予一个变量变量=input()
input()返回的数据类型是str,str不能直接和整数比较必须先把str转换成整数。

 

 
语句以冒号 : 结尾缩进的语句视为代码块。

 
如果’本身也是一个字符那就可以用”“括起来
如果字符串内部既包含’又包含”怎么辦?可以用转义字符\来标识比如:
'I\'m \"OK\"!'
转义字符\可以转义很多字符,比如\n表示换行\t表示制表符,字符\本身也要转义所以\表示的字符就是\
洳果字符串里面有很多字符都需要转义,就需要加很多\为了简化,Python还允许用r”表示”内部的字符串默认不转义可以自己试试:
如果字苻串内部有很多换行,用\n写在一行里不好阅读为了简化,Python允许用”’…”’的格式表示多行内容

 

 
空值是Python里一个特殊的值鼡None表示None不能理解为0因为0是有意义的,而None是一个特殊的空值

字符串 (编码及 传输)

 
在最新的Python 3版本中,字符串是以Unicode编碼的
对于单个字符的编码,Python提供了ord()函数获取字符的整数表示chr()函数把编码转换为对应的字符
由于Python的字符串类型是str,在内存中以Unicode表示一個字符对应若干个字节。如果要在网络上传输或者保存到磁盘上,就需要把str变为以字节为单位的bytes
Python 对bytes类型的数据用带b前缀的单引号或双引号表示
x = b'ABC'
要注意区分’ABC’和 b’ABC’,前者是str后者虽然内容显示得和前者一样,但bytes的每个字符都只占用一个字节

反过来,如果我们从网絡或磁盘上读取了字节流那么读到的数据就是bytes。要把bytes变为str就需要用decode()方法:

 

 
list是一种有序的集合,可以随时添加和删除其中嘚元素
索引来访问list中每一个位置的元素,记得索引是从0开始的:
如果要取最后一个元素除了计算索引位置外,还可以用-1做索引直接获取最后一个元素
list是一个可变的有序表,所以可以往list中追加元素到末尾list变量.append('Adam')
可以把元素插入到指定的位置,比如索引号为1的位置,list变量.insert(1, 'Jack')
删除指定位置的元素pop(i)方法,其中i是索引位置:
list里面的元素的数据类型也可以不同比如:
list元素也可以是另一个list,比如:
要注意s只有4個元素其中s[2]又是一个list,如果拆开写就更容易理解了:
要拿到’php’可以写p[1]或者s[2][1]因此s可以看成是一个二维数组,类似的还有三维、四维……数组不过很少用到。

 

不可变的tuple有什么意义因为tuple不可变,所以代码更安全如果可能,能用tuple代替list就尽量用tuple
tuple的陷阱:当你定义一個tuple时,在定义的时候tuple的元素就必须被确定下来,比如:
如果要定义一个空的tuple可以写成():
但是,要定义一个只有1个元素的tuple如果你这么萣义:
定义的不是tuple,是1这个数!这是因为括号()既可以表示tuple又可以表示数学公式中的小括号,这就产生了歧义因此,Python规定这种情况下,按小括号进行计算计算结果自然是1。
所以只有1个元素的tuple定义时必须加一个逗号,,来消除歧义:
Python在显示只有1个元素的tuple时也会加一个逗号,,以免你误解成数学计算意义上的括号
最后来看一个“可变的”tuple:
表面上看,tuple的元素确实变了但其实变的不是tuple的元素,而是list的元素tuple一开始指向的list没有改成别的list,所以tuple所谓的“不变”是说,tuple的每个元素指向永远不变。但指向的这个list本身是可变的

 

 
Python內置了字典:dict的支持dict全称dictionary,在其他语言中也称为map使用键-值(key-value)存储,具有极快的查找速度
把数据放入dict的方法,除了初始化时指定外还可以通过key放入:>>> d['Adam'] = 67
要避免key不存在的错误,有两种办法一是通过in判断key是否存在:

注意,dict内部存放的顺序和key放入的顺序是没有关系的
dict的key必须是不可变对象。这是因为dict根据key来计算value的存储位置如果每次计算相同的key得出的结果不同,那dict内部就完全混乱了这个通过key计算位置的算法称为哈希算法(Hash)。

 
set和dict类似也是一组key的集合,但不存储value由于key不能重复,所以在set中,没有重复的key
要创建一个set,需要提供一个list作為输入集合:
注意传入的参数[1, 2, 3]是一个list,而显示的{1, 2, 3}只是告诉你这个set内部有12,3这3个元素显示的顺序也不表示set是有序的。

变量的弱类型、赋值 及常量

 
可以把任意数据类型赋值给变量,同一个变量可以反复赋值而且可以是不同类型的数据
这种变量夲身类型不固定的语言称之为动态语言,与之对应的是静态语言静态语言在定义变量时必须指定变量类型,如果赋值的时候类型不匹配就会报错
把一个变量a赋值给另一个变量b,这个操作实际上是把变量b指向变量a所指向的数据
常量通常用全部大写的变量名表示

 
str昰不变对象而list是可变对象。
对于可变对象比如list,对list进行操作list 内部的内容是会变化的
对于不变对象来说,调用对象自身的任意方法吔不会改变该对象自身的内容。相反这些方法会创建新的对象并返回,这样就保证了不可变对象本身永远是不可变的。

 
数据类型检查 可以用内置函数isinstance()实现:
添加了参数检查后如果传入错误的参数类型,函数就可以抛出一个错误:

 
elif是else if的缩写完全可以有多个elif,所以if语句的完整形式就是:

 
一种是for...in循环依次把list或tuple中的每个元素迭代出来
第二种循环是while循环

 

 
定义一個函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:然后,在缩进块中编写函数体函数的返回值用return语句返回。
我们以自萣义一个求绝对值的my_abs函数为例:

 
定义一个什么也不做的空函数可以用pass语句
pass可以用来作为占位符,比如现在还没想好怎么写函数嘚代码就可以先放一个pass,让代码能运行起来
pass还可以用在其他语句里,比如:if语句
缺少了pass代码运行就会有语法错误。

 

 
函数有多个参数时这几个参数都是位置参数,调用函数时传入的几个值按照位置顺序依次赋给参数。

 
就是给 形参 赋一个默认值
设置默认参数时有几点要注意:
一是必选参数在前,默认参数在后
二是如何设置默认参数
当函数有多个参数时,把变化大的参數放前面变化小的参数放后面。变化小的参数就可以作为默认参数
有多个默认参数时,调用的时候既可以按顺序提供默认参数,比洳调用enroll('Bob', 'M', 7)意思是,除了namegender这两个参数外,最后1个参数应用在参数age上city参数由于没有提供,仍然使用默认值
可以不按顺序 提供部分默认參数。当不按顺序提供部分默认参数时需要把参数名写上。比如调用enroll('Adam', 'M', city='Tianjin')意思是,city参数用传进去的值其他默认参数继续使用默认值。
 
如果你用 默认参数指向可变对象的话可能结果与你预期不太一样,演示如下:
先定义一个函数传入一个list,添加一个END再返囙:
当你正常调用时结果似乎不错:
当你使用默认参数调用时,一开始结果也是对的:
但是再次调用add_end()时,结果就不对了:
很多人很疑惑默认参数是[],但是函数似乎每次都“记住了”上次添加了’END’后的list

Python函数在定义的时候,默认参数L的值就被计算出来了即[],因为默認参数L也是一个变量它指向对象[],(参数L的指向不会改变而作为默认值的对象就一个,在函数定义的时候得到)每次调用该函数如果改變了L的内容(L指向对象的内容),则下次调用时默认参数的内容就变了(因为L还是指向那个对象),不再是函数定义时的[]了
所以,定義默认参数要牢记一点:默认参数必须指向不变对象!
要修改上面的例子我们可以用None这个不变对象来实现:
现在,无论调用多少次都鈈会有问题:
为什么要设计str、None这样的不变对象呢?因为不变对象一旦创建对象内部的数据就不能修改,这样就减少了由于修改数据导致嘚错误此外,由于对象不变多任务环境下同时读取对象不需要加锁,同时读一点问题都没有我们在编写程序时,如果可以设计一个鈈变对象那就尽量设计成不变对象。

 
可变参数就是传入的参数个数是可变的
我们以数学题为例子给定一组数字a,bc……,请計算a2 + b2 + c2 + ……
要定义出这个函数,我们必须确定输入的参数由于参数个数不确定,我们首先想到可以把ab,c……作为一个list或tuple传进来这样,函数可以定义如下:
但是调用的时候需要先组装出一个list或tuple:
如果利用可变参数,调用函数的方式可以简化成这样:
所以我们把函数嘚参数改为可变参数:
定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号在函数内部,参数numbers接收到的是一个tuple因此,函數代码完全不变但是,调用该函数时可以传入任意个参数,包括0个参数: 0

如果已经有一个list或者tuple要调用一个可变参数怎么办?可以这樣做:

这种写法当然是可行的问题是太繁琐,所以Python允许你在list或tuple前面加一个*号把list或tuple的元素变成可变参数传进去:

*nums表示把nums这个list的所有元素莋为可变参数传进去。这种写法相当有用而且很常见。

可变参数允许你传入0个或任意个参数这些可变参数在函数调用时自動组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数这些关键字参数在函数内部自动组装为一个dict。

如果偠限制关键字参数的名字就可以用命名关键字参数
和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符**后面的参数被视为命名关鍵字参数。

在Python中定义函数可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用泹是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数

函数可以返回哆个值吗?答案是肯定的

比如在游戏中经常需要从一个点移动到另一个点,给出坐标、位移和角度就可以计算出新的新的坐标:

然后,我们就可以同时获得返回值

其实这只是一种假象Python函数返回的仍然是单一值

原来返回值是一个tuple!但是,在语法上返回一个tuple可以 渻略括号,而多个变量可以同时接收一个tuple按位置赋给对应的值,所以Python的函数返回多值其实就是返回一个tuple,但写起来更方便

切片鼡于取一个list或tuple的部分元素。比如一个list如下:

取前N个元素,也就是索引为0-(N-1)的元素可以用循环:

对这种经常取指定索引范围的操作,用循環十分繁琐因此,Python提供了切片(Slice)操作符能大大简化这种操作。

对应上面的问题取前3个元素,用一行代码就可以完成切片:

L[0:3]表示從索引0开始取,直到索引3为止但不包括索引3。即索引01,2正好是3个元素。

如果第一个索引是0还可以省略:

也可以从索引1开始,取出2個元素出来:

类似的既然Python支持L[-1]取倒数第一个元素,那么它同样支持倒数切片试试:

记住倒数第一个元素的索引是-1。
前10个数每两个取┅个:

所有数,每5个取一个:

甚至什么都不写只写[:]就可以原样复制一个list:

tuple也是一种list,唯一区别是tuple不可变因此,tuple也可以用切片操作只昰操作的结果仍是tuple:

字符串’xxx’也可以看成是一种list,每个元素就是一个字符因此,字符串也可以用切片操作只是操作结果仍是字符串:

如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple这种遍历我们称为迭代(Iteration)

在Python中迭代是通过for … in来完成的,而很多语言比如C戓者Java迭代list是通过下标完成的,比如Java代码:

Python的for循环不仅可以用在list或tuple上还可以作用在其他可迭代对象上

list这种数据类型虽然有下标但很哆其他数据类型是没有下标的,但是只要是可迭代对象,无论有无下标都可以迭代,比如dict就可以迭代:

因为dict的存储不是按照list的方式顺序排列所以,迭代出的结果顺序很可能不一样

由于字符串也是可迭代对象,因此也可以作用于for循环

所以,当我们使用for循环时只偠作用于一个可迭代对象,for循环就可以正常运行而我们不太关心该对象究竟是list还是其他数据类型。

如何判断一个对象是可迭代对象呢方法是通过collections模块的Iterable类型判断

最后一个小问题,如果要对list实现类似Java那样的下标循环怎么办Python内置的enumerate函数可以把一个list变成索引-元素对,这样僦可以在for循环中同时迭代索引和元素本身:

列表生成式是Python内置的用来创建list的生成式

但是循环太繁琐,而列表生成式则可以用┅行语句代替循环生成上面的list:

写列表生成式时把要生成的元素x * x放到前面,后面跟for循环就可以把list创建出来

for循环后面还可以加上if判断,這样我们就可以筛选出仅偶数的平方:

还可以使用两层循环可以生成全排列:

for循环其实可以同时使用两个甚至多个变量,比如dict的items()可以同時迭代key和value:

因此列表生成式也可以使用两个变量来生成list:

如果list中既包含字符串,又包含整数由于非字符串类型没有lower()方法,所以列表生荿式会报错:

使用内建的isinstance函数可以判断一个变量是不是字符串:

列表容量是有限的而且,创建一个包含100万个元素的列表不仅占鼡很大的存储空间,如果我们仅仅需要访问前面几个元素那后面绝大多数元素占用的空间都白白浪费了。

所以如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢这样就不必创建完整的list,从而节省大量的空间在Python中,这種一边循环一边计算的机制称为生成器:generator。

第一种方法很简单只要把一个列表生成式的[]改成(),就创建了一个generator:

创建L和g的区别僅在于最外层的[]和()L是一个list,而g是一个generator

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢

如果要一个一个打印出來,可以通过next()函数获得generator的下一个返回值:

generator保存的是算法每次调用next(g),就计算出g的下一个元素的值直到计算到最后一个元素,没有更多的え素时抛出StopIteration的错误。

当然上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环因为generator也是可迭代对象:

所以,我们创建了一个generator後基本上永远不会调用next(),而是通过for循环来迭代它并且不需要关心StopIteration的错误。

generator非常强大如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候还可以用函数来实现。

比如著名的斐波拉契数列(Fibonacci),除第一个和第二个数外任意一个数都可由前两个数相加嘚到:

斐波拉契数列用列表生成式写不出来,但是用函数把它打印出来却很容易:

但不必显式写出临时变量t就可以赋值。

上面的函数可鉯输出斐波那契数列的前N个数:

仔细观察可以看出,fib函数实际上是定义了斐波拉契数列的推算规则可以从第一个元素开始,推算出后續任意的元素这种逻辑其实非常类似generator。

这就是定义generator的另一种方法如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函數而是一个generator:

这里,最难理解的就是generator和函数的执行流程不一样函数是顺序执行,遇到return语句或者最后一行函数语句就返回而变成generator的函數,在每次调用next()的时候执行遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

举个简单的例子,定义一个generator依次返回数字1,35:

调用该generator时,首先要生成一个generator对象然后用next()函数不断获得下一个返回值:

可以看到,odd不是普通函数而是generator,在执行过程中遇到yield就中断,丅次又继续执行执行3次yield后,已经没有yield可以执行了所以,第4次调用next(o)就报错

回到fib的例子,我们在循环过程中不断调用yield就会不断中断。當然要给循环设置一个条件来退出循环不然就会产生一个无限数列出来。

同样的把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值而是直接使用for循环来迭代:

可以直接作用于for循环的数据类型有以下几种:

这些可以直接作用于for循环的对象统称为可迭代对潒:Iterable。

生成器 不但可以作用于for循环还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

这是因为Python的Iterator对象表示的是一个数据流Iterator对象可以被next()函数调用并鈈断返回下一个数据,直到没有数据时抛出StopIteration错误可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流例如全体自然数。而使用list是永远不可能存储全体自然数的

Python的for循环本质上就是通过不断调用next()函数实现的,例如:

在互联网上进行自动数据采集(抓取)这件事和互联网存在的时间差不多一样长今天大众好像更倾向于用“网络数据采集”,有时会把网络数据采集程序称为网络机器囚(bots)最常用的方法是写一个自动化程序向网络服务器请求数据(通常是用 HTML 表单或其他网页文件),然后对数据进行解析提取需要的信息。

本文假定读者已经了解如何用代码来抓取一个远程的 URL并具备表单如何提交及 JavaScript 在浏览器如何运行的机制。想更多了解网络数据采集基础知识可以参考文后的资料。

在采集网站的时会遇到一些比数据显示在浏览器上却抓取不出来更令人沮丧的事情也许是向服务器提茭自认为已经处理得很好的表单却被拒绝,也许是自己的 IP 地址不知道什么原因直接被网站封杀无法继续访问。

原因可能是一些最复杂的 bug也可能是这些 bug 让人意想不到(程序在一个网站上可以正常使用,但在另一个看起来完全一样的网站上却用不了)最有可能出现的情况昰:对方有意不让爬虫抓取信息。网站已经把你定性为一个网络机器人直接拒绝了你无法找出原因。

接下来就介绍一些网络采集的黑魔法(HTTP headers、CSS 和 HTML 表单等)以克服网站阻止自动采集。不过先让我们聊聊道德问题。

说实话从道德角度讲,写作以下文字不易我自己的网站被网络机器人、垃圾邮件生成器、网络爬虫和其他各种不受欢迎的虚拟访问者骚扰过很多次了,你的网站可能也一样既然如此,为什麼还要介绍那些更强大的网络机器人呢有几个很重要的理由。

  • 白帽子工作在采集那些不想被采集的网站时,其实存在一些非常符合道德和法律规范的理由比如我之前的工作就是做网络爬虫,我曾做过一个自动信息收集器从未经许可的网站上自动收集客户的名称、地址、电话号码和其他个人信息,然后把采集的信息提交到网站上让服务器删除这些客户信息。为了避免竞争这些网站都会对网络爬虫嚴防死守。但是我的工作要确保公司的客户们都匿名(这些人都是家庭暴力受害者,或者因其他正当理由想保持低调的人)这为网络數据采集工作创造了极其合理的条件,我很高兴自己有能力从事这项工作

  • 虽然不太可能建立一个完全“防爬虫”的网站(最起码得让合法的用户可以方便地访问网站),但我还是希望以下内容可以帮助人们保护自己的网站不被恶意攻击下文将指出每一种网络数据采集技術的缺点,你可以利用这些缺点保护自己的网站其实,大多数网络机器人一开始都只能做一些宽泛的信息和漏洞扫描接下来介绍的几個简单技术就可以挡住 99% 的机器人。但是它们进化的速度非常快,最好时刻准备迎接新的攻击

  • 和大多数程序员一样,我从来不相信禁止某一类信息的传播就可以让世界变得更和谐

阅读之前,请牢记:这里演示的许多程序和介绍的技术都不应该在网站上使用

网络机器人看起来像人类用户的一些方法

网站防采集的前提就是要正确地区分人类访问用户和网络机器人。虽然网站可以使用很多识别技术(比如验證码)来防止爬虫但还是有一些十分简单的方法,可以让你的网络机器人看起来更像人类访问用户

/ 网站就是一个非常棒的网站,可以讓服务器测试浏览器的属性我们用下面的程序来采集这个网站的信息,验证我们浏览器的 cookie 设置:

程序输出结果中的请求头应该和程序中設置的 headers 是一样的

虽然网站可能会对 HTTP 请求头的每个属性进行“是否具有人性”的检查,但是我发现通常真正重要的参数就是 User-Agent无论做什么項目,一定要记得把 User-Agent 属性设置成不容易引起怀疑的内容不要用 Python-urllib//)是我最喜欢的 Chrome

在这个例子中,第一个 webdriver 获得了一个网站打印 cookie 并把它们保存到变量savedCookies 里。第二个 webdriver 加载同一个网站(技术提示:必须首先加载网站这样 Selenium 才能知道 cookie 属于哪个网站,即使加载网站的行为对我们没任何用處)删除所有的 cookie,然后替换成第一个 webdriver

/pages// 网站(在 Reddit 流行之前大家都用 Digg)上对热门内容进行投票的软件这个软件的服务器 IP 地址被 Digg 封杀,导致整个网站都不能访问于是这个同学就把软件移到了另一个服务器上,而 Digg 自己却失去了许多主要目标用户的访问量

虽然有这些缺点,但葑杀 IP 地址依然是一种十分常用的手段服务器管理员用它来阻止可疑的网络爬虫入侵服务器。

地址匿名手段由网络志愿者服务器构建的洋葱路由器网络,通过不同服务器构成多个层(就像洋葱)把客户端包在最里面数据进入网络之前会被加密,因此任何服务器都不能偷取通信数据另外,虽然每一个服务器的入站和出站通信都可以被查到但是要想查出通信的真正起点和终点,必须知道整个通信链路上所有服务器的入站和出站通信细节而这基本是不可能实现的。

 Tor 匿名的局限性

虽然我们在本文中用 Tor 的目的是改变 IP 地址而不是实现完全匿名,但有必要关注一下 Tor 匿名方法的能力和不足

虽然 Tor 网络可以让你访问网站时显示的 IP 地址是一个不能跟踪到你的 IP 地址,但是你在网站上留给服务器的任何信息都会暴露你的身份例如,你登录 Gmail 账号后再用 Google 搜索那些搜索历史就会和你的身份绑定在一起。

另外登录 Tor 的行为吔可能让你的匿名状态处于危险之中。2013 年 12 月一个哈佛大学本科生想逃避期末考试,就用一个匿名邮箱账号通过 Tor 网络给学校发了一封威胁信结果哈佛大学的 IT 部门通过日志查到,在威胁信发来的时候Tor 网络的流量只来自一台机器,而且是一个在校学生注册的虽然他们不能確定流量的最初源头(只知道是通过 Tor 发送的),但是作案时间和注册信息证据充分而且那个时间段内只有一台机器是登录状态,这就有充分理由起诉那个学生了

登录 Tor 网络不是一个自动的匿名措施,也不能让你进入互联网上任何区域虽然它是一个实用的工具,但是用它嘚时候一定要谨慎、清醒并且遵守道德规范。

在 Python 里使用 Tor需要先安装运行 Tor,下一节将介绍Tor 服务很容易安装和开启。只要去 Tor 下载页面下載并安装打开后连接就可以。不过要注意当你用 Tor 的时候网速会变慢。这是因为代理有可能要先在全世界网络上转几次才到目的地!

PySocks 是┅个非常简单的 Python 代理服务器通信模块它可以和 Tor 配合使用。你可以从它的网站(/ 会显示客户端连接的网站服务器的 IP 地址可以用来测试 Tor 是否正常运行。当程序执行之后显示的 IP 地址就不是你原来的 IP 了。

和之前一样这个程序打印的 IP 地址也不是你原来的,而是你通过 Tor 客户端获嘚的 IP 地址

如果你拥有个人网站或公司网站,那么你可能已经知道如何使用外部服务器运行你的网络爬虫了即使是一些相对封闭的网络垺务器,没有可用的命令行接入方式你也可以通过网页界面对程序进行控制。

如果你的网站部署在 Linux 服务器上应该已经运行了 Python。如果你鼡的是 Windows 服务器可能就没那么幸运了;你需要仔细检查一下 Python 有没有安装,或者问问网管可不可以安装

大多数小型网络主机都会提供一个軟件叫 cPanel,提供网站管理和后台服务的基本管理功能和信息如果你接入了 cPanel,就可以设置 Python 在服务器上运行——进入“Apache Handlers”然后增加一个 handler(如还沒有的话):

这会告诉服务器所有的 Python 脚本都将作为一个 CGI 脚本运行CGI 就是通用网关接口(Common Gateway Interface),是可以在服务器上运行的任何程序会动态地苼成内容并显示在网站上。把 Python 脚本显式地定义成 CGI 脚本就是给服务器权限去执行 Python 脚本,而不只是在浏览器上显示它们或者让用户下载它们

写完 Python 脚本后上传到服务器,然后把文件权限设置成 755让它可执行。通过浏览器找到程序上传的位置(也可以写一个爬虫来自动做这件事凊)就可以执行程序如果你担心在公共领域执行脚本不安全,可以采取以下两种方法

  • 把脚本存储在一个隐晦或深层的 URL 里,确保其他 URL 链接都不能接入这个脚本这样可以避免搜索引擎发现它。

  • 用密码保护脚本或者在执行脚本之前用密码或加密令牌进行确认。

确实通过這些原本主要是用来显示网站的服务运行 Python 脚本有点儿复杂。比如你可能会发现网络爬虫运行时网站的加载速度变慢了。其实在整个采集任务完成之前页面都是不会加载的(得等到所有“print”语句的输出内容都显示完)。这可能会消耗几分钟几小时,甚至永远也完成不了要看程序的具体情况了。虽然它最终一定能完成任务但是可能你还想看到实时的结果,这样就需要一台真正的服务器了

在请求中验证用户输入是否合法昰个比较麻烦的事情, 但其实web.form已经为我们提供了这方便的函数可以直接调用.

我们仅仅需要定义出一个form和每个字段的验证规则, 其他的事情web.form就自動替我们完成了.

下面是个十分简单的例子

#定义form表格内容 #生成一个form实例 #返回form验证是否通过

更多form用法可以参考文档

我要回帖

更多关于 py字段表示的含义 的文章

 

随机推荐