一 pycurl介绍

pycurl模块为libcurl库提供了一个python接口。libcurl是一个开源免费且方便快捷的基于客户端的url传输库,支持FTP,HTTP,HTTPS,IMAP,IMAPS,LDAP,LDAPS,POP3,POP3S,RTMP,RTSP,SCP等等。libcurl还支持SSL认证,HTTP POST,HTTP PUT,FTP UPLOADING等等。和urllib模块类似,pycurl模块也可以用来获取一个url的对象。pycurl使用了大部分libcurl提供的函数,使得pycurl具有以下特性:

快速  libcurl本身就很快速,pycurl就是对libcurl进行了一次封装,所以pycurl同样很快速。

支持多种协议,SSL,认证和代理选项。pycurl支持大部分libcurl的回调函数。

multi 和 share 接口支持

可以和应用的I/O整合

二 pycurl使用案例

1.安装pycurl

CentOS6 下使用pip install pycurl安装

可以使用ipython来调试

2.获取一个url响应结果

import pycurl

from StringIO import StringIO

buffer=StringIO()

c=pycurl.Curl()

c.setopt(c.URL,'http://pycurl.io/')

c.setopt(c.WRITEFUNCTION,buffer.write)

c.perform()

c.close()

body=buffer.getvalue()

print(body)

  

pycurl本身不会存储url的响应结果,因此,需要设置一个buffer,让pycurl将结果写入到这个buffer中

想要获取调试信息,可以设置

c.setopt(c.VERBOSE, True)

  

 

等同于 curl -v

3.审查响应头

在实际案例中,我们想要根据服务端的编码格式来解码响应结果

import pycurl
import re
try:
from io import BytesIO
except ImportError: from StringIO import StringIO as BytesIO headers={}
def header_function(header_line):
# HTTP standard specifies that headers are encoded in iso-8859-1.
# On Python 2, decoding step can be skipped.
# On Python 3, decoding step is required.
header_line=header_line.decode('iso-8859-1') # Header lines include the first status line (HTTP/1.x ...).
# We are going to ignore all lines that don't have a colon in them.
# This will botch headers that are split on multiple lines...
if ':' not in header_line:
return # Break the header line into header name and value.
name, value = header_line.split(':', 1) # Remove whitespace that may be present.
# Header lines include the trailing newline, and there may be whitespace
# around the colon.
name = name.strip()
value = value.strip() # Header names are case insensitive.
# Lowercase name here.
name = name.lower() # Now we can actually record the header name and value.
headers[name] = value
buffer=BytesIO()
c=pycurl.Curl()
c.setopt(c.URL,'http://pycurl.io')
c.setopt(c.WRITEFUNCTION,buffer.write)
#set our header function
c.setopt(c.HEADERFUNCTION,header_function)
c.perform()
c.close() # Figure out what encoding was sent with the response, if any.
# Check against lowercased header name.
encoding=None
if 'content-type' in headers:
content_type=headers['content-type'].lower()
match=re.search('charset=(\S+)', content_type)
if match:
encoding=match.group(1)
print('Decoding using %s' % encoding) if encoding is None:
# Default encoding for HTML is iso-8859-1.
# Other content types may have different default encoding,
# or in case of binary data, may have no encoding at all.
encoding='iso-8859-1'
print('Assuming encoding is %s' % encoding) body=buffer.getvalue()
# Decode using the encoding we figured out.
print(body.decode(encoding))

  

 
 

4.将响应结果写入到文件

import pycurl

with open('out.html','wb') as f:
c=pycurl.Curl()
c.setopt(c.URL,'http://pycurl.io/')
c.setopt(c.WRITEDATA,f)
c.perform()
c.close()

  

 

这里最重要的部分就是以二进制模式打开文件,这样响应结果可以以字节码写入到文件中,不需要编码和解码。

5.跟踪url跳转

libcurl和pycurl默认不跟踪url跳转。

import pycurl
c=pycurl.Curl()
#Redirects to https://www.python.org/.
c.setopt(c.URL,'http://www.python.org/')
#Follow redirect
c.setopt(c.FOLLOWLOCATION,True)
c.perform()
c.close()

  

 

6.审查响应

import pycurl
try:
from io import BytesIO
except ImportError:
from StringIO import StringIO as BytesIO buffer=BytesIO()
c=pycurl.Curl()
c.setopt(c.URL,'http://www.python.org/')
c.setopt(c.WRITEFUNCTION,buffer.write)
c.perform() #Last used URL
print('Effective_url: %s' %c.getinfo(c.EFFECTIVE_URL))
#HTTP response code
print('Response_code: %d' %c.getinfo(c.RESPONSE_CODE))
#Total time of previous transfer
print('Total_time: %f' %c.getinfo(c.TOTAL_TIME))
#Time from start until name resolving completed
print('Namelookup_time: %f' %c.getinfo(c.NAMELOOKUP_TIME))
#Time from start until remote host or proxy completed
print('Connect_time: %f' %c.getinfo(c.CONNECT_TIME))
#Time from start until SLL/SSH handshake completed
print('SSL/SSH_time: %f' %c.getinfo(c.APPCONNECT_TIME))
#Time from start until just before the transfer begins
print('Pretransfer_time: %f' %c.getinfo(c.PRETRANSFER_TIME))
#Time from start until just when the first byte is received
print('Starttransfer_time: %f' %c.getinfo(c.STARTTRANSFER_TIME))
#Time taken for all redirect steps before the final transfer
print('Redirect_time: %f' %c.getinfo(c.REDIRECT_TIME))
#Total number of redirects that were followed
print('Redirect_count: %d' %c.getinfo(c.REDIRECT_COUNT))
#URL a redirect would take you to,had you enabled redirects
print('Redirect_url: %s' %c.getinfo(c.REDIRECT_URL))
#Number of bytes uploaded
print('Size_upload: %d' %c.getinfo(c.SIZE_UPLOAD))
#Average upload speed
print('Speed_upload: %f' %c.getinfo(c.SPEED_UPLOAD))
#Number of bytes downloaded
print('Size_download: %d' %c.getinfo(c.SIZE_DOWNLOAD))
#Average download speed
print('Speed_download: %f' %c.getinfo(c.SPEED_DOWNLOAD)) #getinfo must be called before close
c.close()

  

# python response_info.py
Effective_url: http://www.python.org/
Response_code: 301
Total_time: 0.105395
Namelookup_time: 0.051208
Connect_time: 0.078317
SSL/SSH_time: 0.000000
Pretransfer_time: 0.078322
Starttransfer_time: 0.105297
Redirect_time: 0.000000
Redirect_count: 0
Redirect_url: https://www.python.org/
Size_upload: 0
Speed_upload: 0.000000
Size_download: 0
Speed_download: 0.000000

  

 
 
 
 

7.发送表单数据

发送表单数据使用POSTFIELDS参数

import pycurl
try:
#python 3
from urllib.parse import urlencode
except ImportError:
from urllib import urlencode c=pycurl.Curl()
c.setopt(c.URL,'http://pycurl.io/tests/testpostvars.php') post_data={'field':'value'}
#Form data must be provided already urlencoded
postfields=urlencode(post_data)
# Sets request method to POST,
# Content-Type header to application/x-www-form-urlencoded
# and data to send in request body.
c.setopt(c.POSTFIELDS, postfields) c.perform()
c.close()

  

 

8.文件上传

上传文件使用HTTPPOST参数,上传一个物理文件,使用FORM_FILE

import pycurl

c = pycurl.Curl()
c.setopt(c.URL, 'http://pycurl.io/tests/testfileupload.php') c.setopt(c.HTTPPOST, [
('fileupload', (
# upload the contents of this file
c.FORM_FILE, __file__,
)),
]) c.perform()
c.close()

  

 

为上传的文件设置不同的文件名和内容类型

import pycurl

c = pycurl.Curl()
c.setopt(c.URL, 'http://pycurl.io/tests/testfileupload.php') c.setopt(c.HTTPPOST, [
('fileupload', (
# upload the contents of this file
c.FORM_FILE, __file__,
# specify a different file name for the upload
c.FORM_FILENAME, 'helloworld.py',
# specify a different content type
c.FORM_CONTENTTYPE, 'application/x-python',
)),
]) c.perform()
c.close()

  

 
 

如果文件数据在内存中,使用BUFFER/BUFFERPTR

import pycurl

c = pycurl.Curl()
c.setopt(c.URL, 'http://pycurl.io/tests/testfileupload.php') c.setopt(c.HTTPPOST, [
('fileupload', (
c.FORM_BUFFER, 'readme.txt',
c.FORM_BUFFERPTR, 'This is a fancy readme file',
)),
]) c.perform()
c.close()

  

 

9.处理FTP协议

import pycurl

c = pycurl.Curl()
c.setopt(c.URL, 'ftp://ftp.sunet.se/')
c.setopt(c.FTP_USE_EPSV, 1)
c.setopt(c.QUOTE, ['cwd pub', 'type i'])
c.perform()
c.close()

  

 

10.Sharing Data 

import pycurl
import threading print >>sys.stderr, 'Testing', pycurl.version class Test(threading.Thread): def __init__(self, share):
threading.Thread.__init__(self)
self.curl = pycurl.Curl()
self.curl.setopt(pycurl.URL, 'http://curl.haxx.se')
self.curl.setopt(pycurl.SHARE, share) def run(self):
self.curl.perform()
self.curl.close() s = pycurl.CurlShare()
s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_COOKIE)
s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_DNS) t1 = Test(s)
t2 = Test(s) t1.start()
t2.start()
del s

  

 

11.使用multi接口

libcurl的easy接口是一个同步的,高效的,上手快的用于文件传输的接口。multi接口是一个异步的接口,它可以使用一个或者多个线程进行多路传输。

multi接口比easy接口多了以下几个功能:

提供一个pull接口。使用libcurl的应用决定哪里何时询问libcurl去接收或者发送数据

在同一个线程中启动多路同步传输而不必使应用程序变得更复杂

使得应用程序同时等待在应用程序本身的文件描述符和libcurl文件描述符上的动作变得简单许多

使得基于事件处理和扩展的传输可以达到上千个并行连接

 

例1

import pycurl

m = pycurl.CurlMulti()
m.handles = []
c1 = pycurl.Curl()
c2 = pycurl.Curl()
c1.setopt(c1.URL, 'http://curl.haxx.se')
c2.setopt(c2.URL, 'http://cnn.com')
c2.setopt(c2.FOLLOWLOCATION, 1)
m.add_handle(c1)
m.add_handle(c2)
m.handles.append(c1)
m.handles.append(c2) num_handles = len(m.handles)
while num_handles:
while 1:
ret, num_handles = m.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM:
break
m.select(1.0) m.remove_handle(c2)
m.remove_handle(c1)
del m.handles
m.close()
c1.close()
c2.close()

  

 

 
 

例2

import os, sys
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
import pycurl urls = (
"http://curl.haxx.se",
"http://www.python.org",
"http://pycurl.sourceforge.net",
"http://pycurl.sourceforge.net/tests/403_FORBIDDEN", # that actually exists ;-)
"http://pycurl.sourceforge.net/tests/404_NOT_FOUND",
) # Read list of URIs from file specified on commandline
try:
urls = open(sys.argv[1], "rb").readlines()
except IndexError:
# No file was specified
pass # init
m = pycurl.CurlMulti()
m.handles = []
for url in urls:
c = pycurl.Curl()
# save info in standard Python attributes
c.url = url.strip()
c.body = StringIO()
c.http_code = -1
m.handles.append(c)
# pycurl API calls
c.setopt(c.URL, c.url)
c.setopt(c.WRITEFUNCTION, c.body.write)
c.setopt(c.FOLLOWLOCATION,True)
m.add_handle(c) # get data
num_handles = len(m.handles)
while num_handles:
while 1:
ret, num_handles = m.perform()
print ret,num_handles
if ret != pycurl.E_CALL_MULTI_PERFORM:
break
# currently no more I/O is pending, could do something in the meantime
# (display a progress bar, etc.)
m.select(1.0) # close handles
for c in m.handles:
# save info in standard Python attributes
c.http_code = c.getinfo(c.HTTP_CODE)
# pycurl API calls
m.remove_handle(c)
c.close()
m.close() # print result
for c in m.handles:
data = c.body.getvalue()
if 0:
print "**********", c.url, "**********"
print data
else:
print "%-53s http_code %3d, %6d bytes" % (c.url, c.http_code, len(data))

  

 
 

例3

import os, sys
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
import pycurl urls = (
"http://curl.haxx.se",
"http://www.python.org",
"http://pycurl.sourceforge.net",
"http://pycurl.sourceforge.net/THIS_HANDLE_IS_CLOSED",
) # init
m = pycurl.CurlMulti()
m.handles = []
for url in urls:
c = pycurl.Curl()
# save info in standard Python attributes
c.url = url
c.body = StringIO()
c.http_code = -1
c.debug = 0
m.handles.append(c)
# pycurl API calls
c.setopt(c.URL, c.url)
c.setopt(c.WRITEFUNCTION, c.body.write)
c.setopt(c.FOLLOWLOCATION,True)
m.add_handle(c) # debug - close a handle
if 1:
c = m.handles[3]
c.debug = 1
c.close() # get data
num_handles = len(m.handles)
while num_handles:
while 1:
ret, num_handles = m.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM:
break
# currently no more I/O is pending, could do something in the meantime
# (display a progress bar, etc.)
m.select(1.0) # close handles
for c in m.handles:
# save info in standard Python attributes
try:
c.http_code = c.getinfo(c.HTTP_CODE)
except pycurl.error:
# handle already closed - see debug above
assert c.debug
c.http_code = -1
# pycurl API calls
if 0:
m.remove_handle(c)
c.close()
elif 0:
# in the C API this is the wrong calling order, but pycurl
# handles this automatically
c.close()
m.remove_handle(c)
else:
# actually, remove_handle is called automatically on close
c.close()
m.close() # print result
for c in m.handles:
data = c.body.getvalue()
if 0:
print "**********", c.url, "**********"
else:
print "%-53s http_code %3d, %6d bytes" % (c.url, c.http_code, len(data))

  

 
 

可以使用multi接口来缩短访问很多url的时间

假设一个文件中包含了很多个url,现在要通过脚本去访问每个url判断返回码是不是200

文件中共有87个url

方法一 使用python的for语句顺序访问每个url

import os,sys
import pycurl
from StringIO import StringIO try:
if sys.argv[1]=="-":
urls=sys.stdin.readlines()
else:
urls=open(sys.argv[1],'rb').readlines()
#print urls
except:
print "Usage: %s check_urls.txt <file with urls to check>" %sys.argv[0]
raise SystemExit class Curl:
def __init__(self,url):
self.url=url
self.body=StringIO()
self.http_code=0 self._curl=pycurl.Curl()
self._curl.setopt(pycurl.URL,self.url)
self._curl.setopt(pycurl.WRITEFUNCTION,self.body.write)
self._curl.setopt(pycurl.FOLLOWLOCATION,True)
self._curl.setopt(pycurl.NOSIGNAL,1) def perform(self):
self._curl.perform() def close(self):
self.http_code=self._curl.getinfo(pycurl.HTTP_CODE)
self._curl.close() for url in urls:
url=url.strip()
if not url or url[0] == '#':
continue
c=Curl(url)
c.perform()
c.close()
print url, c.http_code

  

real    2m46.134s
user 0m0.134s
sys 0m0.185s

  

 
 
 
 

方法二 使用pycurl的CurlMulti()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
from StringIO import StringIO
import pycurl
 
# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
# the libcurl tutorial for more info.
try:
   import signal
   from signal import SIGPIPE,SIG_ING
   signal.signal(signal.SIGPIPE,signal.SIG_IGN)
except ImportError:
   pass
 
 
# need a given txt file contains urls
try:
   if sys.argv[1]=="-":
      urls=sys.stdin.readlines()
   else:
      urls=open(sys.argv[1],'rb').readlines()
   #print urls
except:
   print "Usage: %s check_urls.txt <file with urls to check>" %sys.argv[0]
   raise SystemExit
 
class Curl:
   def __init__(self,url):
       self.url=url
       self.body=StringIO()
       self.http_code=0
 
       self._curl=pycurl.Curl()
       self._curl.setopt(pycurl.URL,self.url)
       self._curl.setopt(pycurl.FOLLOWLOCATION,True)
       self._curl.setopt(pycurl.WRITEFUNCTION,self.body.write)
       self._curl.setopt(pycurl.NOSIGNAL,1)
       self._curl.debug=0
 
   def perform(self):
       self._curl.perform()
 
   def close(self):
      try:
        self.http_code=self._curl.getinfo(pycurl.HTTP_CODE)
      except pycurl.error:
        assert c.debug
        self.http_code=0
      self._curl.close()
 
 
 
def print_result(items):
 
    for in items:
        data=c.body.getvalue()
        if 0:
            print "***************",c.url,"******************"
            print data
        elif 1:
            print "%-60s        %3d     %6d" %(c.url,c.http_code,len(data))
 
 
 
def test_multi():
    handles=[]
    m=pycurl.CurlMulti()
    for url in urls:
        url=url.strip()
        if not url or url[0== '#':
           continue
        c=Curl(url)
        m.add_handle(c._curl)
        handles.append(c)
 
    while 1:
        ret,num_handles=m.perform()
        if ret!= pycurl.E_CALL_MULTI_PERFORM:
           break
 
    while num_handles:
        m.select(5.0)
        while 1:
            ret,num_handles=m.perform()
            if ret!= pycurl.E_CALL_MULTI_PERFORM:
                break
    for in handles:
        c.close()
    m.close()
 
 
    print_result(handles)
 
 
 
 
if 1:
  test_multi()
1
2
3
real    2m46.049s
user    0m0.082s
sys 0m0.132s

在pycurl作者给的案例中,使用CurlMulti()接口处理多个url速度是最快的,但是当url数量多时速度并不快,而且有部分url还不能获取正确的返回值

方法三 使用python的多线程模块

python由于有GIL全局解释器锁的存在,python提供的threading模块不能充分利用多线程的优势,在多核CPU服务器上,统一时刻实际上只有一个线程在运行,其他线程都处于锁定状态。所以python的threading模块不适合用于处理CPU密集型任务,相反,threading线程数据量越多,速度越慢。但是对于I/O密集型或者网络密集型任务,还是可以使用threading模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import os,sys,time
import threading
import Queue
 
try:
   from cStringIO import StringIO
except ImportError:
   from StringIO import StringIO
import pycurl
 
# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
# the libcurl tutorial for more info.
try:
   import signal
   from signal import SIGPIPE,SIG_ING
   signal.signal(signal.SIGPIPE,signal.SIG_IGN)
except ImportError:
   pass
 
 
# need a given txt file contains urls
try
   if sys.argv[1]=="-":
      urls=sys.stdin.readlines()
   else:
      urls=open(sys.argv[1],'rb').readlines()
   #print urls
except:
   print "Usage: %s check_urls.txt <file with urls to check>" %sys.argv[0]
   raise SystemExit
  
class Curl:
   def __init__(self,url):
       self.url=url
       self.body=StringIO()
       self.http_code=0
        
       self._curl=pycurl.Curl()
       self._curl.setopt(pycurl.URL,self.url)
       self._curl.setopt(pycurl.FOLLOWLOCATION,True)
       self._curl.setopt(pycurl.CONNECTTIMEOUT,15)
       self._curl.setopt(pycurl.TIMEOUT,15)
       self._curl.setopt(pycurl.WRITEFUNCTION,self.body.write)
       self._curl.setopt(pycurl.NOSIGNAL,1)
       self._curl.debug=0
    
   def perform(self):
       self._curl.perform()
    
   def close(self):
      try:
        self.http_code=self._curl.getinfo(pycurl.HTTP_CODE)
      except pycurl.error:
        assert c.debug
        self.http_code=0 
      self._curl.close()
 
 
queue=Queue.Queue()
for url in urls:
    url=url.strip()
    if not url or url[0== "#":
       continue
    queue.put(url)
     
assert queue.queue, "no urls are given"
num_urls=len(queue.queue)
#num_conn=min(num_conn,num_urls)
num_conn=num_urls
#assert 1 <= num_conn < = 1000,"invalid number of concurrent connections"
 
class WorkerThread(threading.Thread):
     def __init__(self,queue):
         threading.Thread.__init__(self)
         self.queue=queue
   
     def run(self):
         while 1:
             try:
                url=self.queue.get_nowait()
             except Queue.Empty:
                raise SystemExit
             c=Curl(url)
             c.perform()
             c.close()
             print "http_url:" + url + "\t" + "http_code:" + str(c.http_code)
#start a bunch of threads                
threads=[]
for dummy in range(num_conn):
    t=WorkerThread(queue)
    t.start()
    threads.append(t)
 
#wait for all threads to finish
for thread in threads:
    thread.join()
1
2
3
real    0m10.500s
user    0m0.149s
sys 0m0.196s

可以看到时间明显比以上两种方法所短了很多

所以,对于有大量url需要用pycurl来处理时,应该结合threading模块

参考资料:

http://pycurl.sourceforge.net/

http://pycurl.io/docs/latest/index.html

https://curl.haxx.se/libcurl/

https://curl.haxx.se/libcurl/c/libcurl-multi.html

转python版本的curl工具pycurl学习的更多相关文章

  1. python版本wifi共享工具

    原先不知道win7系统也可以当作无线路由器,既然知道了这个东西那么就搞搞了 使用python写的一个wifi共享工具,还不够完善,有些功能还没做(说明:internet共享连接需要手动设置)..... ...

  2. Metasploit和python两种安全工具的学习笔记

    Metasploit是个好东西 主要参考了<Metasploit渗透测试魔鬼训练营>这本书. 一.先用自己的靶机感受一下该工具的强大 linux靶机的ip如图 按照书上写的配置,如图 然后 ...

  3. Cygwin 版本的 Curl 安装,提取,使用笔记

    Cygwin 版本的 Curl 安装,提取,使用笔记 Cygwin 版本的 Curl 使其恢复 HTTPS 请求功能Cygwin 版本的 Curl 依赖的 DLL 清单提取 Cygwin 版本的 Cu ...

  4. 安装的 Python 版本太多互相干扰?pyenv 建议了解一下。

    写在之前 我们都知道现在的 Python 有 Python2 和 Python3,但是由于各种乱七八糟的原因导致这俩哥们要长期共存,荣辱与共,尴尬的是这哥俩的差异还比较大,在很多时候我们可能要同时用到 ...

  5. 《零基础学习Python制作ArcGIS自定义工具》课程简介

    Python for ArcGIS Python for ArcGIS是借助Python语言实现ArcGIS自动化行为的综合,它不止是如课程标题所述的“制作ArcGIS自定义工具”,还包括使用Pyth ...

  6. Python基础学习之Python主要的数据分析工具总结

    Python主要是依靠众多的第三方库来增强它的数据处理能力的.常用的是Numpy库,Scipy库.Matplotlib库.Pandas库.Scikit-Learn库等. 常规版本的python需要在安 ...

  7. 自动化运维工具ansible-如何设置客户端多python版本问题

    问题:在使用ansible进行管理客户主机时,发现客户主机安装了多个版本的python,并且默认版本为3.0 shell>>cat list 192.168.2.9 shell>&g ...

  8. Python多版本共存管理工具之pyenv

    目录 Table of Contents 1. 安装pyenv 2. 安装Python 3.0 使用python 参考 Table of Contents 经常遇到这样的情况: 系统自带的Python ...

  9. Python—版本和环境的管理工具(Pipenv)

    pipenv简介 虚拟环境本质是一个文件,是为了适应不同的项目而存在.pipenv相当于virtualenv和pip的合体. 整合了 pip+virtualenv+Pipfile,能够自动处理好包的依 ...

随机推荐

  1. 地理课(geography)

    地理课(geography) 题目描述 地理课上,老师给出了一个巨大的地图,由于世界日新月异,会有一些道路在某一时刻被删除,也会有一些道路在某一时刻被修建.这里的道路均为双向的. 老师认为,有一些城市 ...

  2. Python基础教程笔记 第二章

    本章的名字虽然叫列表和元组,但是本章讲的最多的是列表,元祖指讲了很少的一部分.因为元组和列表很多方面都是一样的. 列表和元组的区别:列表可以被修改,元祖不可以被修改. python包含的6种内建序列: ...

  3. 一个html5视频播放器

    具有播放视频,拖拽,自定义右键菜单,上传头像的功能 <!DOCTYPE html><html lang="en"> <head> <met ...

  4. ofbiz数据库表结构设计(1)- PARTY

    ofbiz的精华就在于其数据结构(表结构)的设计.数据结构的通用性也决定了ofbiz几乎可以适用任何企业应用.我们首先来看看PARTY相关的表结构设计. 在ofbiz中,PARTY是个抽象概念,它可以 ...

  5. 十步完全理解 SQL(转载)

    1 SQL是一种声明式语言 SQL 语言是为计算机声明了一个你想从原始数据中获得什么样的结果的一个范例,而不是告诉计算机如何能够得到结果.学好SQL要改变传统函数式编程思想,例如用变量传参.使用循环语 ...

  6. Logger用法

    logger的输出有两种方式:①log.log(Level.INFO,"message")②log.info("mesage")其他级别的输出与此类似. 获得c ...

  7. 一、Ubuntu 简介

    Ubuntu 是一个Linux 系统 Apt-Get apt-get 命令是一个强大的命令行工具,用于同 Ubuntu 的 Advanced Packaging Tool (APT) 一起执行诸如安装 ...

  8. PHP生成随机码

    前几天,做了个小小的实验,生成了一组数据,数据要求是包含1000个元素,每个元素为10个随机的数字加字母的组合. 嗨呀,说写就写,然后用for循环生成了一组数据,看起来还不错,先把代码贴上来. //随 ...

  9. 关于TP中U方法,在wamp中是绝对路径,在nginx中是相对路径?(坑)

    这个问题已多次遇到,关于tp 框架 使用U 方法跳转, 在Nginx 服务器上可能会遇到路由跳转不过去前面带点(如:./xx) 解决这个问题,可以在tp的入口文件 index.php 里定义个常量 d ...

  10. 让cpu占用率曲线听你指挥(多核处理器)

    编程之美 1.1 让cpu占用率曲线听你指挥(多核处理器) [版权声明]转载请注明出处 http://www.cnblogs.com/TenosDoIt/p/3242910.html  [目录] 不考 ...