python 如果往cookielib.curlopt cookiejarr()里手动添加字段?

先来说一下我们学校的网站:
查询成绩需要登录,然后显示各学科成绩,但是只显示成绩而没有绩点,也就是加权平均分。
显然这样手动计算绩点是一件非常麻烦的事情。所以我们可以用python做一个爬虫来解决这个问题。
1.决战前夜
先来准备一下工具:HttpFox插件。
这是一款http协议分析插件,分析页面请求和响应的时间、内容、以及浏览器用到的COOKIE等。
以我为例,安装在火狐上即可,效果如图:
可以非常直观的查看相应的信息。
点击start是开始检测,点击stop暂停检测,点击clear清除内容。
一般在使用之前,点击stop暂停,然后点击clear清屏,确保看到的是访问当前页面获得的数据。
2.深入敌后
下面就去山东大学的成绩查询网站,看一看在登录的时候,到底发送了那些信息。
先来到登录页面,把httpfox打开,clear之后,点击start开启检测:
输入完了个人信息,确保httpfox处于开启状态,然后点击确定提交信息,实现登录。
这个时候可以看到,httpfox检测到了三条信息:
这时点击stop键,确保捕获到的是访问该页面之后反馈的数据,以便我们做爬虫的时候模拟登陆使用。
3.庖丁解牛
乍一看我们拿到了三个数据,两个是GET的一个是POST的,但是它们到底是什么,应该怎么用,我们还一无所知。
所以,我们需要挨个查看一下捕获到的内容。
先看POST的信息:
既然是POST的信息,我们就直接看PostData即可。
可以看到一共POST两个数据,stuid和pwd。
并且从Type的Redirect to可以看出,POST完毕之后跳转到了bks_login2.loginmessage页面。
由此看出,这个数据是点击确定之后提交的表单数据。
点击cookie标签,看看cookie信息:
没错,收到了一个ACCOUNT的cookie,并且在session结束之后自动销毁。
那么提交之后收到了哪些信息呢?
我们来看看后面的两个GET数据。
先看第一个,我们点击content标签可以查看收到的内容,是不是有一种生吞活剥的快感-。-HTML源码暴露无疑了:
看来这个只是显示页面的html源码而已,点击cookie,查看cookie的相关信息:
啊哈,原来html页面的内容是发送了cookie信息之后才接受到的。
再来看看最后一个接收到的信息:
大致看了一下应该只是一个叫做style.css的css文件,对我们没有太大的作用。
4.冷静应战
既然已经知道了我们向服务器发送了什么数据,也知道了我们接收到了什么数据,基本的流程如下:
首先,我们POST学号和密码---&然后返回cookie的值
然后发送cookie给服务器---&返回页面信息。
获取到成绩页面的数据,用正则表达式将成绩和学分单独取出并计算加权平均数。
OK,看上去好像很简单的样纸。那下面我们就来试试看吧。
但是在实验之前,还有一个问题没有解决,就是POST的数据到底发送到了哪里?
再来看一下当初的页面:
很明显是用一个html框架来实现的,也就是说,我们在地址栏看到的地址并不是右边提交表单的地址。
那么怎样才能获得真正的地址-。-右击查看页面源代码:
嗯没错,那个name="w_right"的就是我们要的登录页面。
网站的原来的地址是:
http://jwxt.:7777/zhxt_bks/zhxt_bks.html
所以,真正的表单提交的地址应该是:
http://jwxt.:7777/zhxt_bks/xk_login.html
输入一看,果不其然:
靠居然是清华大学的选课系统。。。目测是我校懒得做页面了就直接借了。。结果连标题都不改一下。。。
但是这个页面依旧不是我们需要的页面,因为我们的POST数据提交到的页面,应该是表单form的ACTION中提交到的页面。
也就是说,我们需要查看源码,来知道POST数据到底发送到了哪里:
嗯,目测这个才是提交POST数据的地址。
整理到地址栏中,完整的地址应该如下:
(获取的方式很简单,在火狐浏览器中直接点击那个链接就能看到这个链接的地址了)
5.小试牛刀
接下来的任务就是:用python模拟发送一个POST的数据并取到返回的cookie值。
关于cookie的操作可以看看这篇博文:
我们先准备一个POST的数据,再准备一个cookie的接收,然后写出源码如下:
# -*- coding: utf-8 -*-
#---------------------------------------
程序:山东大学爬虫
语言:Python 2.7
操作:输入学号和密码
功能:输出成绩的加权平均值也就是绩点
#---------------------------------------
import urllib
import urllib2
import cookielib
cookie = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
#需要POST的数据#
postdata=urllib.urlencode({
'stuid':'',
'pwd':'921030'
#自定义一个请求#
req = urllib2.Request(
url = 'http://jwxt.:7777/pls/wwwbks/bks_login2.login',
data = postdata
#访问该链接#
result = opener.open(req)
#打印返回的内容#
print result.read()
如此这般之后,再看看运行的效果:
ok,如此这般,我们就算模拟登陆成功了。
6.偷天换日
接下来的任务就是用爬虫获取到学生的成绩。
再来看看源网站。
开启HTTPFOX之后,点击查看成绩,发现捕获到了如下的数据:
点击第一个GET的数据,查看内容可以发现Content就是获取到的成绩的内容。
而获取到的页面链接,从页面源代码中右击查看元素,可以看到点击链接之后跳转的页面(火狐浏览器只需要右击,&查看此框架&,即可):
从而可以得到查看成绩的链接如下:
7.万事俱备
现在万事俱备啦,所以只需要把链接应用到爬虫里面,看看能否查看到成绩的页面。
从httpfox可以看到,我们发送了一个cookie才能返回成绩的信息,所以我们就用python模拟一个cookie的发送,以此来请求成绩的信息:
# -*- coding: utf-8 -*-
#---------------------------------------
程序:山东大学爬虫
语言:Python 2.7
操作:输入学号和密码
功能:输出成绩的加权平均值也就是绩点
#---------------------------------------
import urllib
import urllib2
import cookielib
#初始化一个CookieJar来处理Cookie的信息#
cookie = cookielib.CookieJar()
#创建一个新的opener来使用我们的CookieJar#
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
#需要POST的数据#
postdata=urllib.urlencode({
'stuid':'',
'pwd':'921030'
#自定义一个请求#
req = urllib2.Request(
url = 'http://jwxt.:7777/pls/wwwbks/bks_login2.login',
data = postdata
#访问该链接#
result = opener.open(req)
#打印返回的内容#
print result.read()
#打印cookie的值
for item in cookie:
print 'Cookie:Name = '+item.name
print 'Cookie:Value = '+item.value
#访问该链接#
result = opener.open('http://jwxt.:7777/pls/wwwbks/bkscjcx.curscopre')
#打印返回的内容#
print result.read()
按下F5运行即可,看看捕获到的数据吧:
既然这样就没有什么问题了吧,用正则表达式将数据稍稍处理一下,取出学分和相应的分数就可以了。
8.手到擒来
这么一大堆html源码显然是不利于我们处理的,下面要用正则表达式来抠出必须的数据。
关于正则表达式的教程可以看看这个博文:
我们来看看成绩的源码:
既然如此,用正则表达式就易如反掌了。
我们将代码稍稍整理一下,然后用正则来取出数据:
# -*- coding: utf-8 -*-
#---------------------------------------
程序:山东大学爬虫
语言:Python 2.7
操作:输入学号和密码
功能:输出成绩的加权平均值也就是绩点
#---------------------------------------
import urllib
import urllib2
import cookielib
class SDU_Spider:
# 申明相关的属性
def __init__(self):
self.loginUrl = 'http://jwxt.:7777/pls/wwwbks/bks_login2.login'
# 登录的url
self.resultUrl = 'http://jwxt.:7777/pls/wwwbks/bkscjcx.curscopre' # 显示成绩的url
self.cookieJar = cookielib.CookieJar()
# 初始化一个CookieJar来处理Cookie的信息
self.postdata=urllib.urlencode({'stuid':'','pwd':'921030'})
# POST的数据
self.weights = []
#存储权重,也就是学分
self.points = []
#存储分数,也就是成绩
self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))
def sdu_init(self):
# 初始化链接并且获取cookie
myRequest = urllib2.Request(url = self.loginUrl,data = self.postdata)
# 自定义一个请求
result = self.opener.open(myRequest)
# 访问登录页面,获取到必须的cookie的值
result = self.opener.open(self.resultUrl)
# 访问成绩页面,获得成绩的数据
# 打印返回的内容
# print result.read()
self.deal_data(result.read().decode('gbk'))
self.print_data(self.weights);
self.print_data(self.points);
# 将内容从页面代码中抠出来
def deal_data(self,myPage):
myItems = re.findall('&TR&.*?&p.*?&p.*?&p.*?&p.*?&p.*?&(.*?)&/p&.*?&p.*?&p.*?&(.*?)&/p&.*?&/TR&',myPage,re.S)
#获取到学分
for item in myItems:
self.weights.append(item[0].encode('gbk'))
self.points.append(item[1].encode('gbk'))
# 将内容从页面代码中抠出来
def print_data(self,items):
for item in items:
print item
mySpider = SDU_Spider()
mySpider.sdu_init()
水平有限,,正则是有点丑,。运行的效果如图:
ok,接下来的只是数据的处理问题了。。
9.凯旋而归
完整的代码如下,至此一个完整的爬虫项目便完工了。
# -*- coding: utf-8 -*-
#---------------------------------------
程序:山东大学爬虫
语言:Python 2.7
操作:输入学号和密码
功能:输出成绩的加权平均值也就是绩点
#---------------------------------------
import urllib
import urllib2
import cookielib
import string
class SDU_Spider:
# 申明相关的属性
def __init__(self):
self.loginUrl = 'http://jwxt.:7777/pls/wwwbks/bks_login2.login'
# 登录的url
self.resultUrl = 'http://jwxt.:7777/pls/wwwbks/bkscjcx.curscopre' # 显示成绩的url
self.cookieJar = cookielib.CookieJar()
# 初始化一个CookieJar来处理Cookie的信息
self.postdata=urllib.urlencode({'stuid':'','pwd':'921030'})
# POST的数据
self.weights = []
#存储权重,也就是学分
self.points = []
#存储分数,也就是成绩
self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))
def sdu_init(self):
# 初始化链接并且获取cookie
myRequest = urllib2.Request(url = self.loginUrl,data = self.postdata)
# 自定义一个请求
result = self.opener.open(myRequest)
# 访问登录页面,获取到必须的cookie的值
result = self.opener.open(self.resultUrl)
# 访问成绩页面,获得成绩的数据
# 打印返回的内容
# print result.read()
self.deal_data(result.read().decode('gbk'))
self.calculate_date();
# 将内容从页面代码中抠出来
def deal_data(self,myPage):
myItems = re.findall('&TR&.*?&p.*?&p.*?&p.*?&p.*?&p.*?&(.*?)&/p&.*?&p.*?&p.*?&(.*?)&/p&.*?&/TR&',myPage,re.S)
#获取到学分
for item in myItems:
self.weights.append(item[0].encode('gbk'))
self.points.append(item[1].encode('gbk'))
#计算绩点,如果成绩还没出来,或者成绩是优秀良好,就不运算该成绩
def calculate_date(self):
point = 0.0
weight = 0.0
for i in range(len(self.points)):
if(self.points[i].isdigit()):
point += string.atof(self.points[i])*string.atof(self.weights[i])
weight += string.atof(self.weights[i])
print point/weight
mySpider = SDU_Spider()
mySpider.sdu_init()
阅读(...) 评论()Python实战中阶(一)——爬取网页的一点分享 | 杰杰 · 杰杰网络磨坊主 || 网站建设|武汉网站建设|网站制作 --武汉专业网站建设工作室
承接大中小型网站项目
1. 大中小型网站设计、开发与维护(电子商务网站、企业网站、门户网站...)
2. Flash设计、制作与维护
3. 重构网站前端为DIV+CSS
4. 优化数据库
5. 服务器维护
博客最新日志
命运就算颠沛流离
命运就算曲折离奇
命运就算恐吓着你做人...
昨天踢完球(其实应该算是前天了),打车回家。
经过徐家汇,停...
一直想写一篇这样的文章,一篇关于我对世界的认识,没有出过国,...
很久之前为公司爬取过一次数据,受益匪浅,记忆犹新,分享...
今天和leader一起聊了很多,他给我讲了他初来公司时的苦涩,到慢...
Python实战中阶(一)——爬取网页的一点分享
Python实战中阶(一)——爬取网页的一点分享
很久之前为公司爬取过一次数据,受益匪浅,记忆犹新,分享一下。
一 工欲善其事必先利其器
首先,这里介绍几个工具
httplib python中的http客户端
urllib 对httplib的简单封装,可以很方便的请求一个url
urllib2 urllib的增强而不是升级,全名定制请求header
re python对正则表达式的支持
cookielib python的一个cookie处理器
Cookie python的一个cookie对象,可以很容易的对cookie合成和解析
这几个工具都是python内核中作为库或模块存在的,直接import即可。
1. httplib
httplib是python对http的简单实现,请求头的内容以及响应都需要人肉完全组装和解析,我们一般不用,因为对于抓取普通页面httplib还能应付,但是涉及到302、cookie验证的登录、防盗链等就会很吃力。
但是,这里我可以简单介绍一下,假设我们要抓取杰杰的博客首页。
import httplib
port = httplib.HTTP_PORT
url = '/' #这里其实是cgi相对路径和参数列表,类似php的REQUEST_URI
hl = httplib.HTTPConnection(host, port)
hl.request('GET', url)
resp = hl.getresponse() #拿到响应的对象,包括响应头、正文和其它的方法
respHtml = resp.read() #响应正文
hl.close()
当拿到正文后分析,就可以拿到想要抓取的内容了。如果是涉及到登录或者防盗链要家referer,需要手动拼装http请求头,然后作为request方法的第四个参数发送请求。
特别要注意的是,最后一句关闭连接,虽然系统会帮助关闭连接和垃圾回收,或者由于超时自动关闭,但是当连接过多,就会占用系统非常多的资源,不管是打开http连接、tcp连接,还是文件资源等,打开资源后关闭是个非常好的习惯。
urllib其实是对httplib的一个简单封装,无需创建request对象、请求和关闭连接,当然也屏蔽了许多细节,使我们没办法构建自定义的http头,我们在后面的使用也不会用到,这里简单介绍一下。
import urllib
fh = urllib.urlopen(url)
#请求了url对应的资源,并返回一个file handle。
respHtml = fh.read() #响应正文
fh.close()
fh其实是一个类似本地的文件资源的连接,拥有read(),readline(),fileno()等方法,另外值得关注的是info(), getcode() 和 geturl()这三个方法,这是普通文件资源所没有的,info()用来读取部分响应的内容,getcode(),用来获取响应的http code从而判断该url是否可用,而geturl()用来获取真实的url地址,因为原始地址可能会被重定向。
info()返回的是一个mimetools.Message对象,详情可以。
另外值得注意的一点便是,urllib可以很容易实现代理,当抓取机的ip被目标server屏蔽时,便变得非常有用。
用法之一便是实现bash的全局变量
export http_proxy=":3218"
这时,使用urlopen的时候,便会自动走该代理。而如果想自定义的代理或者不想走代理时,可以这样:
proxies = {'http': ':3128'}
fh = urllib.urlopen(url, proxies = proxies) #自定义代理
fh = urllib.urlopen(url, proxies = {}) #不使用代理
fh = urllib.urlopen(url, proxies = Null)
#系统代理,也就是判断使用有bash http_proxy全局变量
如果不传第二个参数,也会用系统的代理设置。
当然urllib还有其它很多方法,比如说urlencode()等,大家可以自己研究。
3. urllib2
这是需要重点介绍的,也是我们之后会用到来抓取页面的常用工具之一。
从字面上来看,urllib2应该是urllib的升级版本,但为什么python会让这两个版本在python共存呢?其实是这样的,urllib2是urllib的增强版,而不是升级版,urllib用来满足日常简单应用,而urllib2可以支持更高级的特性,主要是可以像urlopen()传一个urllib2.Request对象,这样开发者可以自行合成请求头,以及对cookie的支持以及重定向的处理,http 认证等等,当然,这些操作会比使用httplib简单很多很多。后面对于要使用的地方会详细介绍。
另外,这里还要介绍一下,对于使用命令比较多,或者php curl的开发者,应该会非常熟悉,有他实在是太方便了,但是在python中由于强大的urllib2存在,以及pycurl需要依赖很多包,导致pycurl在py中安装非常繁琐,这里不详细介绍,有兴趣的可以了解一下,使用和php curl类似,当让还有基于urllib2开发的的,也是很强大的。
import urllib2
req = urllib2.Request('/')
fh = urllib2.urlopen(req) #也可以直接传字符串的url
respHtml = fh.read()
fh.close()
python对正则表达式的支持模块。如果http库有选择的余地外,re几乎是没有选择余地的工具。因为有正则表达式的存在,所以让我们可以很灵活的去抠取抓取过来的完整html中所需要的部分。
当然,这篇文章不会详细解释正则表达式,因为如果要系统的介绍正则表达式,或许可以写一本书了。这里只简单提一下我们后面会用到的python正则表达式的用法。
<pile()。如果正则表达式比较多,请一定要先用这个方法先行编译正则表达式,之后再正则表达式的使用就会很非常快,因为大家都知道,python文件在第一次运行会分别创建一个字节码文件,如果正则表达式作为字符串的时候,在运行时才会被编译,是会影响到python的执行速度的。
bodyRe =re.compile(r'(.*)', re.I | re.S)
#re.I是匹配模式不区别大小写,而re.S可以改变.的行为让其匹配默认不会匹配的换行符。
compile()返回的是一个re对象,该对象拥有re库的search(), match(), findall()等方法,这三个方法,在后面会被频繁的用到,生成被编译的re对象还有一个好处是调用方法不用再传入字符串的正则表达式。
search()主要用来校验正则表达式能否匹配字符串中的一段,通常用来判断该页面是否有我需要的内容。
match = re.search(r'&div class="post"', respHtml)
#如果有被正则表达式匹配的一段,则返回匹配对象,否则为None
if match is not None:
print match.group() #匹配成功
match()用来判断字符串是否完全被一个正则表达式匹配,后面用的比较少。
#seach()和match()区别主要是一个是用正则表达式进行查找,一个是用来匹配字符串
re.match(r'post', 'class="post"') #匹配失败
re.search(r'post', 'class="post"') #匹配成功
findall()用来搜索正则表达式在字符串中的所有匹配,并返回一个列表,如果没有任何匹配,则返回一个空列表。
print re.findall(r'p-\d', "p-1, p-2, p-3, p-4")
#['p-1', 'p-2', 'p-3', 'p-4']
#如果有子组(正则表达式中有括号)的正则表达式会更复杂
print re.findall(r'p-(\d(\d?))', "p-12, p-22, p-33, p-4")
#[('12', '2'), ('22', '2'), ('33', '3'), ('4', '')]
带有子组的正则表达式,findall()返回的列表中的每个元素为一个元组,正则表达式中有几个子组,元组中就会有几个元素,第一个元素为第一个括号中的子组匹配到的元素,以此类推。
findall()和search()是有类似之处的,都是搜索正则表达式在字符串中的匹配,但是findall()返回一个列表,search()返回一个匹配对象,而且findall()返回的列表中有所有匹配,而search()只返回第一个匹配的匹配对象。
5. cookielib和Cookie
这两个库后面会详细提到,这里不过多介绍。
二 真刀真枪,厮杀秘籍
上面介绍了下面会用到的大部分工具,这里重点讲一下用urllib2来爬取复杂的网络情况,特别是破解防盗链和登录。
import urllib2
req = urllib2.Request('/') #创建一个request对象
1. Refere验证
req.add_header('Refere', '/')
2. User-Agent验证
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.79 Safari/537.1')
3. Cookie验证
有些页面是需要验证cookie的,比如防盗链的资源或者需要登录的页面。
import cookielib
cj = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
opener.open(req)
#如果这次请求又返回set-cookie,
#那么当第二次请求带上cj时,就会自动将这次设置的cookie带入到请求中
如果想自己手动设置cookie,可以用Cookie库
import Cookie
c = Cookie.SimpleCookie()
c['name'] = 'admin' #cookie名为name,值为admin
c['name']['domain'] = '.'
c['name']['path'] = '/'
#可以用c.outpu()检验cookie的正确性
#另外还有expires(过期时间,不穿为回话),comment,max-age,secure,version,httponly ,因为这些参数主要用于浏览器客户端,不涉及这次的开发,有兴趣的同学可以详细查看RFC 2109。
cj.set_cookie(c) #再次请求,就会带上name这个cookie
不过这一步的意义不大,因为服务器需要验证的cookie,通常我们是无法知道具体值的,所以没办法自己拼装。
4. 返回码(HTTP Code)
如果抓取的页面不存在,或者dns无法解析等问题,会抛出urllib2.HTTPError或者urllib2.URLError异常。
通常来说是dns无法解析会抛出URLError,也是IOError的基类,而404,500等会抛出HTTPError异常,它是URLError的基类。
urllib2.urlopen('/errpage')
except urllib2.HTTPError, e:
print e.code #返回的http code
except urllib2.URLError, e:
5. 调试模式
代码在跑的时候,我们并不知道程序在后台的动作,打开调试模式,可以查看后台的发包和收包状况
httpHandler
= urllib2.HTTPHandler(debuglevel = 1)
httpshandler = urllib2.HTTPSHandler(debuglevel = 1)
= urllib2.build_opener(httpHandler, httpshandler)
fh = opener.urlopen('/')
6. 防封ip神器——代理
当抓取机在某台服务器上告诉抓取时,很有可能被网站管理员发现很有可能会被封掉ip,这时代理就能派上用场了。
proxyHandler
= urllib2.proxyHandler({'http': ':3128/'})
#设置带用户名和密码的代理
proxyAuthHandler = urllib2.proxyBasicAuthHandler()
proxyAuthHandler.add_password('realm', ':3128', 'user', 'password') #需要用户名密码的代理
proxyHandler1
= urllib2.proxyHandler({'http': 'http://user:password@:3128/'}) #另外一种形式设置用户名和密码
= urllib2.build_opener(proxyHandler)
fh = opener.urlopen('/')
7. 防封ip终极神器——sleep()
就算设置了代理,代理的ip也有可能被封,还有另外一种终极的办法来防止被封,那便是使用time库的sleep()函数。
import time
for i in range(1:10):
... #抓取逻辑
time.sleep(5) #单位为秒
休眠时间可根据实际情况动态的调整,最开始10s,慢慢调成9s, 8s…… 不要调到太小以防止被封
如果有一台很好的机器来抓取网页,单线程的方式就实在是太大材小用了,让多线程来好好利用吧。
这里会用到threading库的Thread类。
def worker(arg1, arg2):
...#抓取逻辑
#创建一个线程
th = threading.Thread(target=worker, args=(arg1, arg2))
th.start() #启动线程
th.join() #等待线程结束,则主进程结束
因为python的线程是跑在虚拟机上的,并非真的多线程,所以对于系统资源的利用率上和本身多进程机制还是有一定问题的,另外对多核cpu的利用也不好,但是相对于单线程还是好多了。
抓取网页,总的来说有三个问题要解决,破解防盗链,防止IP被封和html过于复杂。
前面两个问题上文已经给出了解决方案,至于最后一个问题,就要开发者实地评估和能很好的使用正则表达式了,但是虽然能很好的使用正则表达式,一般的页面都能爬出来,但是正则表达式无法解决嵌套的问题,python有个库,xml.dom,但是它对html的结构要求非常严格,如果标签没有结束或者标签属性不对都会抛出异常。
有一个比较好的解析html的工具——,有兴趣的同学可以详细研究,非常好用。
最后,本文没有讲到数据落地的问题,也就是爬到了,但是没有保存起来,博主之后会写一篇关于的博客,敬请关注!
Lorem Ipsum is simply dum
industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknow the industry's standard dummy text ever since the 1500s
Lorem Ipsum is simply dum
industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknow the industry's standard dummy text ever since the 1500s
Lorem Ipsum is simply dum
industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknow the industry's standard dummy text ever since the 1500s
There are many variations
If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet.
It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to
Copyright (C) . All rights reserved.

我要回帖

更多关于 python 字段为空 的文章

 

随机推荐