网络速度是我们日常生活和工作中非常重要的一部分。如果正在寻找一种简单而又高效的方法来测量你的网络速度,可以使用Python来进行网速测试,通过使用speedtest库来实现。

不仅如此,我们还将演示如何使用这些数据来评估网络性能,并提出优化建议。无论你是个专业人士还是业余爱好者,都了解如何使用Python来提升网络效率。

# -*- coding: utf-8 -*-import os
import re
import csv
import sys
import math
import errno
import signal
import socket
import timeit
import datetime
import platform
import threading
import xml.parsers.expattry:import gzipGZIP_BASE = gzip.GzipFile
except ImportError:gzip = NoneGZIP_BASE = object__version__ = '2.1.3'class FakeShutdownEvent(object):"""Class to fake a threading.Event.isSet so that users of this moduleare not required to register their own threading.Event()"""@staticmethoddef isSet():"Dummy method to always return false"""return False# Some global variables we use
DEBUG = False
_GLOBAL_DEFAULT_TIMEOUT = object()
PY25PLUS = sys.version_info[:2] >= (2, 5)
PY26PLUS = sys.version_info[:2] >= (2, 6)
PY32PLUS = sys.version_info[:2] >= (3, 2)# Begin import game to handle Python 2 and Python 3
try:import json
except ImportError:try:import simplejson as jsonexcept ImportError:json = Nonetry:import xml.etree.ElementTree as ETtry:from xml.etree.ElementTree import _Element as ET_Elementexcept ImportError:pass
except ImportError:from xml.dom import minidom as DOMfrom xml.parsers.expat import ExpatErrorET = Nonetry:from urllib2 import (urlopen, Request, HTTPError, URLError,AbstractHTTPHandler, ProxyHandler,HTTPDefaultErrorHandler, HTTPRedirectHandler,HTTPErrorProcessor, OpenerDirector)
except ImportError:from urllib.request import (urlopen, Request, HTTPError, URLError,AbstractHTTPHandler, ProxyHandler,HTTPDefaultErrorHandler, HTTPRedirectHandler,HTTPErrorProcessor, OpenerDirector)try:from httplib import HTTPConnection, BadStatusLine
except ImportError:from http.client import HTTPConnection, BadStatusLinetry:from httplib import HTTPSConnection
except ImportError:try:from http.client import HTTPSConnectionexcept ImportError:HTTPSConnection = Nonetry:from httplib import FakeSocket
except ImportError:FakeSocket = Nonetry:from Queue import Queue
except ImportError:from queue import Queuetry:from urlparse import urlparse
except ImportError:from urllib.parse import urlparsetry:from urlparse import parse_qs
except ImportError:try:from urllib.parse import parse_qsexcept ImportError:from cgi import parse_qstry:from hashlib import md5
except ImportError:from md5 import md5try:from argparse import ArgumentParser as ArgParserfrom argparse import SUPPRESS as ARG_SUPPRESSPARSER_TYPE_INT = intPARSER_TYPE_STR = strPARSER_TYPE_FLOAT = float
except ImportError:from optparse import OptionParser as ArgParserfrom optparse import SUPPRESS_HELP as ARG_SUPPRESSPARSER_TYPE_INT = 'int'PARSER_TYPE_STR = 'string'PARSER_TYPE_FLOAT = 'float'try:from cStringIO import StringIOBytesIO = None
except ImportError:try:from StringIO import StringIOBytesIO = Noneexcept ImportError:from io import StringIO, BytesIOtry:import __builtin__except ImportError:import builtinsfrom io import TextIOWrapper, FileIOclass _Py3Utf8Output(TextIOWrapper):"""UTF-8 encoded wrapper around stdout for py3, to overrideASCII stdout"""def __init__(self, f, **kwargs):buf = FileIO(f.fileno(), 'w')super(_Py3Utf8Output, self).__init__(buf,encoding='utf8',errors='strict')def write(self, s):super(_Py3Utf8Output, self).write(s)self.flush()_py3_print = getattr(builtins, 'print')try:_py3_utf8_stdout = _Py3Utf8Output(sys.stdout)_py3_utf8_stderr = _Py3Utf8Output(sys.stderr)except OSError:# sys.stdout/sys.stderr is not a compatible stdout/stderr object# just use it and hope things go ok_py3_utf8_stdout = sys.stdout_py3_utf8_stderr = sys.stderrdef to_utf8(v):"""No-op encode to utf-8 for py3"""return vdef print_(*args, **kwargs):"""Wrapper function for py3 to print, with a utf-8 encoded stdout"""if kwargs.get('file') == sys.stderr:kwargs['file'] = _py3_utf8_stderrelse:kwargs['file'] = kwargs.get('file', _py3_utf8_stdout)_py3_print(*args, **kwargs)
else:del __builtin__def to_utf8(v):"""Encode value to utf-8 if possible for py2"""try:return v.encode('utf8', 'strict')except AttributeError:return vdef print_(*args, **kwargs):"""The new-style print function for Python 2.4 and 2.5.Taken from https://pypi.python.org/pypi/six/Modified to set encoding to UTF-8 always, and to flush after write"""fp = kwargs.pop("file", sys.stdout)if fp is None:returndef write(data):if not isinstance(data, basestring):data = str(data)# If the file has an encoding, encode unicode with it.encoding = 'utf8'  # Always trust UTF-8 for outputif (isinstance(fp, file) andisinstance(data, unicode) andencoding is not None):errors = getattr(fp, "errors", None)if errors is None:errors = "strict"data = data.encode(encoding, errors)fp.write(data)fp.flush()want_unicode = Falsesep = kwargs.pop("sep", None)if sep is not None:if isinstance(sep, unicode):want_unicode = Trueelif not isinstance(sep, str):raise TypeError("sep must be None or a string")end = kwargs.pop("end", None)if end is not None:if isinstance(end, unicode):want_unicode = Trueelif not isinstance(end, str):raise TypeError("end must be None or a string")if kwargs:raise TypeError("invalid keyword arguments to print()")if not want_unicode:for arg in args:if isinstance(arg, unicode):want_unicode = Truebreakif want_unicode:newline = unicode("\n")space = unicode(" ")else:newline = "\n"space = " "if sep is None:sep = spaceif end is None:end = newlinefor i, arg in enumerate(args):if i:write(sep)write(arg)write(end)if PY32PLUS:etree_iter = ET.Element.iter
elif PY25PLUS:etree_iter = ET_Element.getiteratorif PY26PLUS:thread_is_alive = threading.Thread.is_alive
else:thread_is_alive = threading.Thread.isAlive# Exception "constants" to support Python 2 through Python 3
try:import ssltry:CERT_ERROR = (ssl.CertificateError,)except AttributeError:CERT_ERROR = tuple()HTTP_ERRORS = ((HTTPError, URLError, socket.error, ssl.SSLError, BadStatusLine) +CERT_ERROR)
except ImportError:ssl = NoneHTTP_ERRORS = (HTTPError, URLError, socket.error, BadStatusLine)class SpeedtestException(Exception):"""Base exception for this module"""class SpeedtestCLIError(SpeedtestException):"""Generic exception for raising errors during CLI operation"""class SpeedtestHTTPError(SpeedtestException):"""Base HTTP exception for this module"""class SpeedtestConfigError(SpeedtestException):"""Configuration XML is invalid"""class SpeedtestServersError(SpeedtestException):"""Servers XML is invalid"""class ConfigRetrievalError(SpeedtestHTTPError):"""Could not retrieve config.php"""class ServersRetrievalError(SpeedtestHTTPError):"""Could not retrieve speedtest-servers.php"""class InvalidServerIDType(SpeedtestException):"""Server ID used for filtering was not an integer"""class NoMatchedServers(SpeedtestException):"""No servers matched when filtering"""class SpeedtestMiniConnectFailure(SpeedtestException):"""Could not connect to the provided speedtest mini server"""class InvalidSpeedtestMiniServer(SpeedtestException):"""Server provided as a speedtest mini server does not actually appearto be a speedtest mini server"""class ShareResultsConnectFailure(SpeedtestException):"""Could not connect to speedtest.net API to POST results"""class ShareResultsSubmitFailure(SpeedtestException):"""Unable to successfully POST results to speedtest.net API afterconnection"""class SpeedtestUploadTimeout(SpeedtestException):"""testlength configuration reached during uploadUsed to ensure the upload halts when no additional data should be sent"""class SpeedtestBestServerFailure(SpeedtestException):"""Unable to determine best server"""class SpeedtestMissingBestServer(SpeedtestException):"""get_best_server not called or not able to determine best server"""def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,source_address=None):"""Connect to *address* and return the socket object.Convenience function.  Connect to *address* (a 2-tuple ``(host,port)``) and return the socket object.  Passing the optional*timeout* parameter will set the timeout on the socket instancebefore attempting to connect.  If no *timeout* is supplied, theglobal default timeout setting returned by :func:`getdefaulttimeout`is used.  If *source_address* is set it must be a tuple of (host, port)for the socket to bind as a source address before making the connection.An host of '' or port 0 tells the OS to use the default.Largely vendored from Python 2.7, modified to work with Python 2.4"""host, port = addresserr = Nonefor res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):af, socktype, proto, canonname, sa = ressock = Nonetry:sock = socket.socket(af, socktype, proto)if timeout is not _GLOBAL_DEFAULT_TIMEOUT:sock.settimeout(float(timeout))if source_address:sock.bind(source_address)sock.connect(sa)return sockexcept socket.error:err = get_exception()if sock is not None:sock.close()if err is not None:raise errelse:raise socket.error("getaddrinfo returns an empty list")class SpeedtestHTTPConnection(HTTPConnection):"""Custom HTTPConnection to support source_address acrossPython 2.4 - Python 3"""def __init__(self, *args, **kwargs):source_address = kwargs.pop('source_address', None)timeout = kwargs.pop('timeout', 10)self._tunnel_host = NoneHTTPConnection.__init__(self, *args, **kwargs)self.source_address = source_addressself.timeout = timeoutdef connect(self):"""Connect to the host and port specified in __init__."""try:self.sock = socket.create_connection((self.host, self.port),self.timeout,self.source_address)except (AttributeError, TypeError):self.sock = create_connection((self.host, self.port),self.timeout,self.source_address)if self._tunnel_host:self._tunnel()if HTTPSConnection:class SpeedtestHTTPSConnection(HTTPSConnection):"""Custom HTTPSConnection to support source_address acrossPython 2.4 - Python 3"""default_port = 443def __init__(self, *args, **kwargs):source_address = kwargs.pop('source_address', None)timeout = kwargs.pop('timeout', 10)self._tunnel_host = NoneHTTPSConnection.__init__(self, *args, **kwargs)self.timeout = timeoutself.source_address = source_addressdef connect(self):"Connect to a host on a given (SSL) port."try:self.sock = socket.create_connection((self.host, self.port),self.timeout,self.source_address)except (AttributeError, TypeError):self.sock = create_connection((self.host, self.port),self.timeout,self.source_address)if self._tunnel_host:self._tunnel()if ssl:try:kwargs = {}if hasattr(ssl, 'SSLContext'):if self._tunnel_host:kwargs['server_hostname'] = self._tunnel_hostelse:kwargs['server_hostname'] = self.hostself.sock = self._context.wrap_socket(self.sock, **kwargs)except AttributeError:self.sock = ssl.wrap_socket(self.sock)try:self.sock.server_hostname = self.hostexcept AttributeError:passelif FakeSocket:# Python 2.4/2.5 supporttry:self.sock = FakeSocket(self.sock, socket.ssl(self.sock))except AttributeError:raise SpeedtestException('This version of Python does not support HTTPS/SSL ''functionality')else:raise SpeedtestException('This version of Python does not support HTTPS/SSL ''functionality')def _build_connection(connection, source_address, timeout, context=None):"""Cross Python 2.4 - Python 3 callable to build an ``HTTPConnection`` or``HTTPSConnection`` with the args we needCalled from ``http(s)_open`` methods of ``SpeedtestHTTPHandler`` or``SpeedtestHTTPSHandler``"""def inner(host, **kwargs):kwargs.update({'source_address': source_address,'timeout': timeout})if context:kwargs['context'] = contextreturn connection(host, **kwargs)return innerclass SpeedtestHTTPHandler(AbstractHTTPHandler):"""Custom ``HTTPHandler`` that can build a ``HTTPConnection`` with theargs we need for ``source_address`` and ``timeout``"""def __init__(self, debuglevel=0, source_address=None, timeout=10):AbstractHTTPHandler.__init__(self, debuglevel)self.source_address = source_addressself.timeout = timeoutdef http_open(self, req):return self.do_open(_build_connection(SpeedtestHTTPConnection,self.source_address,self.timeout),req)http_request = AbstractHTTPHandler.do_request_class SpeedtestHTTPSHandler(AbstractHTTPHandler):"""Custom ``HTTPSHandler`` that can build a ``HTTPSConnection`` with theargs we need for ``source_address`` and ``timeout``"""def __init__(self, debuglevel=0, context=None, source_address=None,timeout=10):AbstractHTTPHandler.__init__(self, debuglevel)self._context = contextself.source_address = source_addressself.timeout = timeoutdef https_open(self, req):return self.do_open(_build_connection(SpeedtestHTTPSConnection,self.source_address,self.timeout,context=self._context,),req)https_request = AbstractHTTPHandler.do_request_def build_opener(source_address=None, timeout=10):"""Function similar to ``urllib2.build_opener`` that will buildan ``OpenerDirector`` with the explicit handlers we want,``source_address`` for binding, ``timeout`` and our custom`User-Agent`"""printer('Timeout set to %d' % timeout, debug=True)if source_address:source_address_tuple = (source_address, 0)printer('Binding to source address: %r' % (source_address_tuple,),debug=True)else:source_address_tuple = Nonehandlers = [ProxyHandler(),SpeedtestHTTPHandler(source_address=source_address_tuple,timeout=timeout),SpeedtestHTTPSHandler(source_address=source_address_tuple,timeout=timeout),HTTPDefaultErrorHandler(),HTTPRedirectHandler(),HTTPErrorProcessor()]opener = OpenerDirector()opener.addheaders = [('User-agent', build_user_agent())]for handler in handlers:opener.add_handler(handler)return openerclass GzipDecodedResponse(GZIP_BASE):"""A file-like object to decode a response encoded with the gzipmethod, as described in RFC 1952.Largely copied from ``xmlrpclib``/``xmlrpc.client`` and modifiedto work for py2.4-py3"""def __init__(self, response):# response doesn't support tell() and read(), required by# GzipFileif not gzip:raise SpeedtestHTTPError('HTTP response body is gzip encoded, ''but gzip support is not available')IO = BytesIO or StringIOself.io = IO()while 1:chunk = response.read(1024)if len(chunk) == 0:breakself.io.write(chunk)self.io.seek(0)gzip.GzipFile.__init__(self, mode='rb', fileobj=self.io)def close(self):try:gzip.GzipFile.close(self)finally:self.io.close()def get_exception():"""Helper function to work with py2.4-py3 for getting the currentexception in a try/except block"""return sys.exc_info()[1]def distance(origin, destination):"""Determine distance between 2 sets of [lat,lon] in km"""lat1, lon1 = originlat2, lon2 = destinationradius = 6371  # kmdlat = math.radians(lat2 - lat1)dlon = math.radians(lon2 - lon1)a = (math.sin(dlat / 2) * math.sin(dlat / 2) +math.cos(math.radians(lat1)) *math.cos(math.radians(lat2)) * math.sin(dlon / 2) *math.sin(dlon / 2))c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))d = radius * creturn ddef build_user_agent():"""Build a Mozilla/5.0 compatible User-Agent string"""ua_tuple = ('Mozilla/5.0','(%s; U; %s; en-us)' % (platform.platform(),platform.architecture()[0]),'Python/%s' % platform.python_version(),'(KHTML, like Gecko)','speedtest-cli/%s' % __version__)user_agent = ' '.join(ua_tuple)printer('User-Agent: %s' % user_agent, debug=True)return user_agentdef build_request(url, data=None, headers=None, bump='0', secure=False):"""Build a urllib2 request objectThis function automatically adds a User-Agent header to all requests"""if not headers:headers = {}if url[0] == ':':scheme = ('http', 'https')[bool(secure)]schemed_url = '%s%s' % (scheme, url)else:schemed_url = urlif '?' in url:delim = '&'else:delim = '?'# WHO YOU GONNA CALL? CACHE BUSTERS!final_url = '%s%sx=%s.%s' % (schemed_url, delim,int(timeit.time.time() * 1000),bump)headers.update({'Cache-Control': 'no-cache',})printer('%s %s' % (('GET', 'POST')[bool(data)], final_url),debug=True)return Request(final_url, data=data, headers=headers)def catch_request(request, opener=None):"""Helper function to catch common exceptions encountered whenestablishing a connection with a HTTP/HTTPS request"""if opener:_open = opener.openelse:_open = urlopentry:uh = _open(request)if request.get_full_url() != uh.geturl():printer('Redirected to %s' % uh.geturl(), debug=True)return uh, Falseexcept HTTP_ERRORS:e = get_exception()return None, edef get_response_stream(response):"""Helper function to return either a Gzip reader if``Content-Encoding`` is ``gzip`` otherwise the response itself"""try:getheader = response.headers.getheaderexcept AttributeError:getheader = response.getheaderif getheader('content-encoding') == 'gzip':return GzipDecodedResponse(response)return responsedef get_attributes_by_tag_name(dom, tag_name):"""Retrieve an attribute from an XML document and return it in aconsistent formatOnly used with xml.dom.minidom, which is likely only to be usedwith python versions older than 2.5"""elem = dom.getElementsByTagName(tag_name)[0]return dict(list(elem.attributes.items()))def print_dots(shutdown_event):"""Built in callback function used by Thread classes for printingstatus"""def inner(current, total, start=False, end=False):if shutdown_event.isSet():returnsys.stdout.write('.')if current + 1 == total and end is True:sys.stdout.write('\n')sys.stdout.flush()return innerdef do_nothing(*args, **kwargs):passclass HTTPDownloader(threading.Thread):"""Thread class for retrieving a URL"""def __init__(self, i, request, start, timeout, opener=None,shutdown_event=None):threading.Thread.__init__(self)self.request = requestself.result = [0]self.starttime = startself.timeout = timeoutself.i = iif opener:self._opener = opener.openelse:self._opener = urlopenif shutdown_event:self._shutdown_event = shutdown_eventelse:self._shutdown_event = FakeShutdownEvent()def run(self):try:if (timeit.default_timer() - self.starttime) <= self.timeout:f = self._opener(self.request)while (not self._shutdown_event.isSet() and(timeit.default_timer() - self.starttime) <=self.timeout):self.result.append(len(f.read(10240)))if self.result[-1] == 0:breakf.close()except IOError:passexcept HTTP_ERRORS:passclass HTTPUploaderData(object):"""File like object to improve cutting off the upload once the timeouthas been reached"""def __init__(self, length, start, timeout, shutdown_event=None):self.length = lengthself.start = startself.timeout = timeoutif shutdown_event:self._shutdown_event = shutdown_eventelse:self._shutdown_event = FakeShutdownEvent()self._data = Noneself.total = [0]def pre_allocate(self):chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'multiplier = int(round(int(self.length) / 36.0))IO = BytesIO or StringIOtry:self._data = IO(('content1=%s' %(chars * multiplier)[0:int(self.length) - 9]).encode())except MemoryError:raise SpeedtestCLIError('Insufficient memory to pre-allocate upload data. Please ''use --no-pre-allocate')@propertydef data(self):if not self._data:self.pre_allocate()return self._datadef read(self, n=10240):if ((timeit.default_timer() - self.start) <= self.timeout andnot self._shutdown_event.isSet()):chunk = self.data.read(n)self.total.append(len(chunk))return chunkelse:raise SpeedtestUploadTimeout()def __len__(self):return self.lengthclass HTTPUploader(threading.Thread):"""Thread class for putting a URL"""def __init__(self, i, request, start, size, timeout, opener=None,shutdown_event=None):threading.Thread.__init__(self)self.request = requestself.request.data.start = self.starttime = startself.size = sizeself.result = 0self.timeout = timeoutself.i = iif opener:self._opener = opener.openelse:self._opener = urlopenif shutdown_event:self._shutdown_event = shutdown_eventelse:self._shutdown_event = FakeShutdownEvent()def run(self):request = self.requesttry:if ((timeit.default_timer() - self.starttime) <= self.timeout andnot self._shutdown_event.isSet()):try:f = self._opener(request)except TypeError:# PY24 expects a string or buffer# This also causes issues with Ctrl-C, but we will concede# for the moment that Ctrl-C on PY24 isn't immediaterequest = build_request(self.request.get_full_url(),data=request.data.read(self.size))f = self._opener(request)f.read(11)f.close()self.result = sum(self.request.data.total)else:self.result = 0except (IOError, SpeedtestUploadTimeout):self.result = sum(self.request.data.total)except HTTP_ERRORS:self.result = 0class SpeedtestResults(object):"""Class for holding the results of a speedtest, including:Download speedUpload speedPing/Latency to test serverData about server that the test was run againstAdditionally this class can return a result data as a dictionary or CSV,as well as submit a POST of the result data to the speedtest.net APIto get a share results image link."""def __init__(self, download=0, upload=0, ping=0, server=None, client=None,opener=None, secure=False):self.download = downloadself.upload = uploadself.ping = pingif server is None:self.server = {}else:self.server = serverself.client = client or {}self._share = Noneself.timestamp = '%sZ' % datetime.datetime.utcnow().isoformat()self.bytes_received = 0self.bytes_sent = 0if opener:self._opener = openerelse:self._opener = build_opener()self._secure = securedef __repr__(self):return repr(self.dict())def share(self):"""POST data to the speedtest.net API to obtain a share resultslink"""if self._share:return self._sharedownload = int(round(self.download / 1000.0, 0))ping = int(round(self.ping, 0))upload = int(round(self.upload / 1000.0, 0))# Build the request to send results back to speedtest.net# We use a list instead of a dict because the API expects parameters# in a certain orderapi_data = ['recommendedserverid=%s' % self.server['id'],'ping=%s' % ping,'screenresolution=','promo=','download=%s' % download,'screendpi=','upload=%s' % upload,'testmethod=http','hash=%s' % md5(('%s-%s-%s-%s' %(ping, upload, download, '297aae72')).encode()).hexdigest(),'touchscreen=none','startmode=pingselect','accuracy=1','bytesreceived=%s' % self.bytes_received,'bytessent=%s' % self.bytes_sent,'serverid=%s' % self.server['id'],]headers = {'Referer': 'http://c.speedtest.net/flash/speedtest.swf'}request = build_request('://www.speedtest.net/api/api.php',data='&'.join(api_data).encode(),headers=headers, secure=self._secure)f, e = catch_request(request, opener=self._opener)if e:raise ShareResultsConnectFailure(e)response = f.read()code = f.codef.close()if int(code) != 200:raise ShareResultsSubmitFailure('Could not submit results to ''speedtest.net')qsargs = parse_qs(response.decode())resultid = qsargs.get('resultid')if not resultid or len(resultid) != 1:raise ShareResultsSubmitFailure('Could not submit results to ''speedtest.net')self._share = 'http://www.speedtest.net/result/%s.png' % resultid[0]return self._sharedef dict(self):"""Return dictionary of result data"""return {'download': self.download,'upload': self.upload,'ping': self.ping,'server': self.server,'timestamp': self.timestamp,'bytes_sent': self.bytes_sent,'bytes_received': self.bytes_received,'share': self._share,'client': self.client,}@staticmethoddef csv_header(delimiter=','):"""Return CSV Headers"""row = ['Server ID', 'Sponsor', 'Server Name', 'Timestamp', 'Distance','Ping', 'Download', 'Upload', 'Share', 'IP Address']out = StringIO()writer = csv.writer(out, delimiter=delimiter, lineterminator='')writer.writerow([to_utf8(v) for v in row])return out.getvalue()def csv(self, delimiter=','):"""Return data in CSV format"""data = self.dict()out = StringIO()writer = csv.writer(out, delimiter=delimiter, lineterminator='')row = [data['server']['id'], data['server']['sponsor'],data['server']['name'], data['timestamp'],data['server']['d'], data['ping'], data['download'],data['upload'], self._share or '', self.client['ip']]writer.writerow([to_utf8(v) for v in row])return out.getvalue()def json(self, pretty=False):"""Return data in JSON format"""kwargs = {}if pretty:kwargs.update({'indent': 4,'sort_keys': True})return json.dumps(self.dict(), **kwargs)class Speedtest(object):"""Class for performing standard speedtest.net testing operations"""def __init__(self, config=None, source_address=None, timeout=10,secure=False, shutdown_event=None):self.config = {}self._source_address = source_addressself._timeout = timeoutself._opener = build_opener(source_address, timeout)self._secure = secureif shutdown_event:self._shutdown_event = shutdown_eventelse:self._shutdown_event = FakeShutdownEvent()self.get_config()if config is not None:self.config.update(config)self.servers = {}self.closest = []self._best = {}self.results = SpeedtestResults(client=self.config['client'],opener=self._opener,secure=secure,)@propertydef best(self):if not self._best:self.get_best_server()return self._bestdef get_config(self):"""Download the speedtest.net configuration and return only the datawe are interested in"""headers = {}if gzip:headers['Accept-Encoding'] = 'gzip'request = build_request('://www.speedtest.net/speedtest-config.php',headers=headers, secure=self._secure)uh, e = catch_request(request, opener=self._opener)if e:raise ConfigRetrievalError(e)configxml_list = []stream = get_response_stream(uh)while 1:try:configxml_list.append(stream.read(1024))except (OSError, EOFError):raise ConfigRetrievalError(get_exception())if len(configxml_list[-1]) == 0:breakstream.close()uh.close()if int(uh.code) != 200:return Noneconfigxml = ''.encode().join(configxml_list)printer('Config XML:\n%s' % configxml, debug=True)try:try:root = ET.fromstring(configxml)except ET.ParseError:e = get_exception()raise SpeedtestConfigError('Malformed speedtest.net configuration: %s' % e)server_config = root.find('server-config').attribdownload = root.find('download').attribupload = root.find('upload').attrib# times = root.find('times').attribclient = root.find('client').attribexcept AttributeError:try:root = DOM.parseString(configxml)except ExpatError:e = get_exception()raise SpeedtestConfigError('Malformed speedtest.net configuration: %s' % e)server_config = get_attributes_by_tag_name(root, 'server-config')download = get_attributes_by_tag_name(root, 'download')upload = get_attributes_by_tag_name(root, 'upload')# times = get_attributes_by_tag_name(root, 'times')client = get_attributes_by_tag_name(root, 'client')ignore_servers = [int(i) for i in server_config['ignoreids'].split(',') if i]ratio = int(upload['ratio'])upload_max = int(upload['maxchunkcount'])up_sizes = [32768, 65536, 131072, 262144, 524288, 1048576, 7340032]sizes = {'upload': up_sizes[ratio - 1:],'download': [350, 500, 750, 1000, 1500, 2000, 2500,3000, 3500, 4000]}size_count = len(sizes['upload'])upload_count = int(math.ceil(upload_max / size_count))counts = {'upload': upload_count,'download': int(download['threadsperurl'])}threads = {'upload': int(upload['threads']),'download': int(server_config['threadcount']) * 2}length = {'upload': int(upload['testlength']),'download': int(download['testlength'])}self.config.update({'client': client,'ignore_servers': ignore_servers,'sizes': sizes,'counts': counts,'threads': threads,'length': length,'upload_max': upload_count * size_count})try:self.lat_lon = (float(client['lat']), float(client['lon']))except ValueError:raise SpeedtestConfigError('Unknown location: lat=%r lon=%r' %(client.get('lat'), client.get('lon')))printer('Config:\n%r' % self.config, debug=True)return self.configdef get_servers(self, servers=None, exclude=None):"""Retrieve a the list of speedtest.net servers, optionally filteredto servers matching those specified in the ``servers`` argument"""if servers is None:servers = []if exclude is None:exclude = []self.servers.clear()for server_list in (servers, exclude):for i, s in enumerate(server_list):try:server_list[i] = int(s)except ValueError:raise InvalidServerIDType('%s is an invalid server type, must be int' % s)urls = ['://www.speedtest.net/speedtest-servers-static.php','http://c.speedtest.net/speedtest-servers-static.php','://www.speedtest.net/speedtest-servers.php','http://c.speedtest.net/speedtest-servers.php',]headers = {}if gzip:headers['Accept-Encoding'] = 'gzip'errors = []for url in urls:try:request = build_request('%s?threads=%s' % (url,self.config['threads']['download']),headers=headers,secure=self._secure)uh, e = catch_request(request, opener=self._opener)if e:errors.append('%s' % e)raise ServersRetrievalError()stream = get_response_stream(uh)serversxml_list = []while 1:try:serversxml_list.append(stream.read(1024))except (OSError, EOFError):raise ServersRetrievalError(get_exception())if len(serversxml_list[-1]) == 0:breakstream.close()uh.close()if int(uh.code) != 200:raise ServersRetrievalError()serversxml = ''.encode().join(serversxml_list)printer('Servers XML:\n%s' % serversxml, debug=True)try:try:try:root = ET.fromstring(serversxml)except ET.ParseError:e = get_exception()raise SpeedtestServersError('Malformed speedtest.net server list: %s' % e)elements = etree_iter(root, 'server')except AttributeError:try:root = DOM.parseString(serversxml)except ExpatError:e = get_exception()raise SpeedtestServersError('Malformed speedtest.net server list: %s' % e)elements = root.getElementsByTagName('server')except (SyntaxError, xml.parsers.expat.ExpatError):raise ServersRetrievalError()for server in elements:try:attrib = server.attribexcept AttributeError:attrib = dict(list(server.attributes.items()))if servers and int(attrib.get('id')) not in servers:continueif (int(attrib.get('id')) in self.config['ignore_servers']or int(attrib.get('id')) in exclude):continuetry:d = distance(self.lat_lon,(float(attrib.get('lat')),float(attrib.get('lon'))))except Exception:continueattrib['d'] = dtry:self.servers[d].append(attrib)except KeyError:self.servers[d] = [attrib]breakexcept ServersRetrievalError:continueif (servers or exclude) and not self.servers:raise NoMatchedServers()return self.serversdef set_mini_server(self, server):"""Instead of querying for a list of servers, set a link to aspeedtest mini server"""urlparts = urlparse(server)name, ext = os.path.splitext(urlparts[2])if ext:url = os.path.dirname(server)else:url = serverrequest = build_request(url)uh, e = catch_request(request, opener=self._opener)if e:raise SpeedtestMiniConnectFailure('Failed to connect to %s' %server)else:text = uh.read()uh.close()extension = re.findall('upload_?[Ee]xtension: "([^"]+)"',text.decode())if not extension:for ext in ['php', 'asp', 'aspx', 'jsp']:try:f = self._opener.open('%s/speedtest/upload.%s' % (url, ext))except Exception:passelse:data = f.read().strip().decode()if (f.code == 200 andlen(data.splitlines()) == 1 andre.match('size=[0-9]', data)):extension = [ext]breakif not urlparts or not extension:raise InvalidSpeedtestMiniServer('Invalid Speedtest Mini Server: ''%s' % server)self.servers = [{'sponsor': 'Speedtest Mini','name': urlparts[1],'d': 0,'url': '%s/speedtest/upload.%s' % (url.rstrip('/'), extension[0]),'latency': 0,'id': 0}]return self.serversdef get_closest_servers(self, limit=5):"""Limit servers to the closest speedtest.net servers based ongeographic distance"""if not self.servers:self.get_servers()for d in sorted(self.servers.keys()):for s in self.servers[d]:self.closest.append(s)if len(self.closest) == limit:breakelse:continuebreakprinter('Closest Servers:\n%r' % self.closest, debug=True)return self.closestdef get_best_server(self, servers=None):"""Perform a speedtest.net "ping" to determine which speedtest.netserver has the lowest latency"""if not servers:if not self.closest:servers = self.get_closest_servers()servers = self.closestif self._source_address:source_address_tuple = (self._source_address, 0)else:source_address_tuple = Noneuser_agent = build_user_agent()results = {}for server in servers:cum = []url = os.path.dirname(server['url'])stamp = int(timeit.time.time() * 1000)latency_url = '%s/latency.txt?x=%s' % (url, stamp)for i in range(0, 3):this_latency_url = '%s.%s' % (latency_url, i)printer('%s %s' % ('GET', this_latency_url),debug=True)urlparts = urlparse(latency_url)try:if urlparts[0] == 'https':h = SpeedtestHTTPSConnection(urlparts[1],source_address=source_address_tuple)else:h = SpeedtestHTTPConnection(urlparts[1],source_address=source_address_tuple)headers = {'User-Agent': user_agent}path = '%s?%s' % (urlparts[2], urlparts[4])start = timeit.default_timer()h.request("GET", path, headers=headers)r = h.getresponse()total = (timeit.default_timer() - start)except HTTP_ERRORS:e = get_exception()printer('ERROR: %r' % e, debug=True)cum.append(3600)continuetext = r.read(9)if int(r.status) == 200 and text == 'test=test'.encode():cum.append(total)else:cum.append(3600)h.close()avg = round((sum(cum) / 6) * 1000.0, 3)results[avg] = servertry:fastest = sorted(results.keys())[0]except IndexError:raise SpeedtestBestServerFailure('Unable to connect to servers to ''test latency.')best = results[fastest]best['latency'] = fastestself.results.ping = fastestself.results.server = bestself._best.update(best)printer('Best Server:\n%r' % best, debug=True)return bestdef download(self, callback=do_nothing, threads=None):"""Test download speed against speedtest.netA ``threads`` value of ``None`` will fall back to those dictatedby the speedtest.net configuration"""urls = []for size in self.config['sizes']['download']:for _ in range(0, self.config['counts']['download']):urls.append('%s/random%sx%s.jpg' %(os.path.dirname(self.best['url']), size, size))request_count = len(urls)requests = []for i, url in enumerate(urls):requests.append(build_request(url, bump=i, secure=self._secure))max_threads = threads or self.config['threads']['download']in_flight = {'threads': 0}def producer(q, requests, request_count):for i, request in enumerate(requests):thread = HTTPDownloader(i,request,start,self.config['length']['download'],opener=self._opener,shutdown_event=self._shutdown_event)while in_flight['threads'] >= max_threads:timeit.time.sleep(0.001)thread.start()q.put(thread, True)in_flight['threads'] += 1callback(i, request_count, start=True)finished = []def consumer(q, request_count):_is_alive = thread_is_alivewhile len(finished) < request_count:thread = q.get(True)while _is_alive(thread):thread.join(timeout=0.001)in_flight['threads'] -= 1finished.append(sum(thread.result))callback(thread.i, request_count, end=True)q = Queue(max_threads)prod_thread = threading.Thread(target=producer,args=(q, requests, request_count))cons_thread = threading.Thread(target=consumer,args=(q, request_count))start = timeit.default_timer()prod_thread.start()cons_thread.start()_is_alive = thread_is_alivewhile _is_alive(prod_thread):prod_thread.join(timeout=0.001)while _is_alive(cons_thread):cons_thread.join(timeout=0.001)stop = timeit.default_timer()self.results.bytes_received = sum(finished)self.results.download = ((self.results.bytes_received / (stop - start)) * 8.0)if self.results.download > 100000:self.config['threads']['upload'] = 8return self.results.downloaddef upload(self, callback=do_nothing, pre_allocate=True, threads=None):"""Test upload speed against speedtest.netA ``threads`` value of ``None`` will fall back to those dictatedby the speedtest.net configuration"""sizes = []for size in self.config['sizes']['upload']:for _ in range(0, self.config['counts']['upload']):sizes.append(size)# request_count = len(sizes)request_count = self.config['upload_max']requests = []for i, size in enumerate(sizes):# We set ``0`` for ``start`` and handle setting the actual# ``start`` in ``HTTPUploader`` to get better measurementsdata = HTTPUploaderData(size,0,self.config['length']['upload'],shutdown_event=self._shutdown_event)if pre_allocate:data.pre_allocate()headers = {'Content-length': size}requests.append((build_request(self.best['url'], data, secure=self._secure,headers=headers),size))max_threads = threads or self.config['threads']['upload']in_flight = {'threads': 0}def producer(q, requests, request_count):for i, request in enumerate(requests[:request_count]):thread = HTTPUploader(i,request[0],start,request[1],self.config['length']['upload'],opener=self._opener,shutdown_event=self._shutdown_event)while in_flight['threads'] >= max_threads:timeit.time.sleep(0.001)thread.start()q.put(thread, True)in_flight['threads'] += 1callback(i, request_count, start=True)finished = []def consumer(q, request_count):_is_alive = thread_is_alivewhile len(finished) < request_count:thread = q.get(True)while _is_alive(thread):thread.join(timeout=0.001)in_flight['threads'] -= 1finished.append(thread.result)callback(thread.i, request_count, end=True)q = Queue(threads or self.config['threads']['upload'])prod_thread = threading.Thread(target=producer,args=(q, requests, request_count))cons_thread = threading.Thread(target=consumer,args=(q, request_count))start = timeit.default_timer()prod_thread.start()cons_thread.start()_is_alive = thread_is_alivewhile _is_alive(prod_thread):prod_thread.join(timeout=0.1)while _is_alive(cons_thread):cons_thread.join(timeout=0.1)stop = timeit.default_timer()self.results.bytes_sent = sum(finished)self.results.upload = ((self.results.bytes_sent / (stop - start)) * 8.0)return self.results.uploaddef ctrl_c(shutdown_event):"""Catch Ctrl-C key sequence and set a SHUTDOWN_EVENT for our threadedoperations"""def inner(signum, frame):shutdown_event.set()printer('\nCancelling...', error=True)sys.exit(0)return innerdef version():"""Print the version"""printer('speedtest-cli %s' % __version__)printer('Python %s' % sys.version.replace('\n', ''))sys.exit(0)def csv_header(delimiter=','):"""Print the CSV Headers"""printer(SpeedtestResults.csv_header(delimiter=delimiter))sys.exit(0)def parse_args():"""Function to handle building and parsing of command line arguments"""description = ('Command line interface for testing internet bandwidth using ''speedtest.net.\n''------------------------------------------------------------''--------------\n''https://github.com/sivel/speedtest-cli')parser = ArgParser(description=description)# Give optparse.OptionParser an `add_argument` method for# compatibility with argparse.ArgumentParsertry:parser.add_argument = parser.add_optionexcept AttributeError:passparser.add_argument('--no-download', dest='download', default=True,action='store_const', const=False,help='Do not perform download test')parser.add_argument('--no-upload', dest='upload', default=True,action='store_const', const=False,help='Do not perform upload test')parser.add_argument('--single', default=False, action='store_true',help='Only use a single connection instead of ''multiple. This simulates a typical file ''transfer.')parser.add_argument('--bytes', dest='units', action='store_const',const=('byte', 8), default=('bit', 1),help='Display values in bytes instead of bits. Does ''not affect the image generated by --share, nor ''output from --json or --csv')parser.add_argument('--share', action='store_true',help='Generate and provide a URL to the speedtest.net ''share results image, not displayed with --csv')parser.add_argument('--simple', action='store_true', default=False,help='Suppress verbose output, only show basic ''information')parser.add_argument('--csv', action='store_true', default=False,help='Suppress verbose output, only show basic ''information in CSV format. Speeds listed in ''bit/s and not affected by --bytes')parser.add_argument('--csv-delimiter', default=',', type=PARSER_TYPE_STR,help='Single character delimiter to use in CSV ''output. Default ","')parser.add_argument('--csv-header', action='store_true', default=False,help='Print CSV headers')parser.add_argument('--json', action='store_true', default=False,help='Suppress verbose output, only show basic ''information in JSON format. Speeds listed in ''bit/s and not affected by --bytes')parser.add_argument('--list', action='store_true',help='Display a list of speedtest.net servers ''sorted by distance')parser.add_argument('--server', type=PARSER_TYPE_INT, action='append',help='Specify a server ID to test against. Can be ''supplied multiple times')parser.add_argument('--exclude', type=PARSER_TYPE_INT, action='append',help='Exclude a server from selection. Can be ''supplied multiple times')parser.add_argument('--mini', help='URL of the Speedtest Mini server')parser.add_argument('--source', help='Source IP address to bind to')parser.add_argument('--timeout', default=10, type=PARSER_TYPE_FLOAT,help='HTTP timeout in seconds. Default 10')parser.add_argument('--secure', action='store_true',help='Use HTTPS instead of HTTP when communicating ''with speedtest.net operated servers')parser.add_argument('--no-pre-allocate', dest='pre_allocate',action='store_const', default=True, const=False,help='Do not pre allocate upload data. Pre allocation ''is enabled by default to improve upload ''performance. To support systems with ''insufficient memory, use this option to avoid a ''MemoryError')parser.add_argument('--version', action='store_true',help='Show the version number and exit')parser.add_argument('--debug', action='store_true',help=ARG_SUPPRESS, default=ARG_SUPPRESS)options = parser.parse_args()if isinstance(options, tuple):args = options[0]else:args = optionsreturn argsdef validate_optional_args(args):"""Check if an argument was provided that depends on a module that maynot be part of the Python standard library.If such an argument is supplied, and the module does not exist, exitwith an error stating which module is missing."""optional_args = {'json': ('json/simplejson python module', json),'secure': ('SSL support', HTTPSConnection),}for arg, info in optional_args.items():if getattr(args, arg, False) and info[1] is None:raise SystemExit('%s is not installed. --%s is ''unavailable' % (info[0], arg))def printer(string, quiet=False, debug=False, error=False, **kwargs):"""Helper function print a string with various features"""if debug and not DEBUG:returnif debug:if sys.stdout.isatty():out = '\033[1;30mDEBUG: %s\033[0m' % stringelse:out = 'DEBUG: %s' % stringelse:out = stringif error:kwargs['file'] = sys.stderrif not quiet:print_(out, **kwargs)def shell():"""Run the full speedtest.net test"""global DEBUGshutdown_event = threading.Event()signal.signal(signal.SIGINT, ctrl_c(shutdown_event))args = parse_args()# Print the version and exitif args.version:version()if not args.download and not args.upload:raise SpeedtestCLIError('Cannot supply both --no-download and ''--no-upload')if len(args.csv_delimiter) != 1:raise SpeedtestCLIError('--csv-delimiter must be a single character')if args.csv_header:csv_header(args.csv_delimiter)validate_optional_args(args)debug = getattr(args, 'debug', False)if debug == 'SUPPRESSHELP':debug = Falseif debug:DEBUG = Trueif args.simple or args.csv or args.json:quiet = Trueelse:quiet = Falseif args.csv or args.json:machine_format = Trueelse:machine_format = False# Don't set a callback if we are running quietlyif quiet or debug:callback = do_nothingelse:callback = print_dots(shutdown_event)printer('Retrieving speedtest.net configuration...', quiet)try:speedtest = Speedtest(source_address=args.source,timeout=args.timeout,secure=args.secure)except (ConfigRetrievalError,) + HTTP_ERRORS:printer('Cannot retrieve speedtest configuration', error=True)raise SpeedtestCLIError(get_exception())if args.list:try:speedtest.get_servers()except (ServersRetrievalError,) + HTTP_ERRORS:printer('Cannot retrieve speedtest server list', error=True)raise SpeedtestCLIError(get_exception())for _, servers in sorted(speedtest.servers.items()):for server in servers:line = ('%(id)5s) %(sponsor)s (%(name)s, %(country)s) ''[%(d)0.2f km]' % server)try:printer(line)except IOError:e = get_exception()if e.errno != errno.EPIPE:raisesys.exit(0)printer('Testing from %(isp)s (%(ip)s)...' % speedtest.config['client'],quiet)if not args.mini:printer('Retrieving speedtest.net server list...', quiet)try:speedtest.get_servers(servers=args.server, exclude=args.exclude)except NoMatchedServers:raise SpeedtestCLIError('No matched servers: %s' %', '.join('%s' % s for s in args.server))except (ServersRetrievalError,) + HTTP_ERRORS:printer('Cannot retrieve speedtest server list', error=True)raise SpeedtestCLIError(get_exception())except InvalidServerIDType:raise SpeedtestCLIError('%s is an invalid server type, must ''be an int' % ', '.join('%s' % s for s in args.server))if args.server and len(args.server) == 1:printer('Retrieving information for the selected server...', quiet)else:printer('Selecting best server based on ping...', quiet)speedtest.get_best_server()elif args.mini:speedtest.get_best_server(speedtest.set_mini_server(args.mini))results = speedtest.resultsprinter('Hosted by %(sponsor)s (%(name)s) [%(d)0.2f km]: ''%(latency)s ms' % results.server, quiet)if args.download:printer('Testing download speed', quiet,end=('', '\n')[bool(debug)])speedtest.download(callback=callback,threads=(None, 1)[args.single])printer('Download: %0.2f M%s/s' %((results.download / 1000.0 / 1000.0) / args.units[1],args.units[0]),quiet)else:printer('Skipping download test', quiet)if args.upload:printer('Testing upload speed', quiet,end=('', '\n')[bool(debug)])speedtest.upload(callback=callback,pre_allocate=args.pre_allocate,threads=(None, 1)[args.single])printer('Upload: %0.2f M%s/s' %((results.upload / 1000.0 / 1000.0) / args.units[1],args.units[0]),quiet)else:printer('Skipping upload test', quiet)printer('Results:\n%r' % results.dict(), debug=True)if not args.simple and args.share:results.share()if args.simple:printer('Ping: %s ms\nDownload: %0.2f M%s/s\nUpload: %0.2f M%s/s' %(results.ping,(results.download / 1000.0 / 1000.0) / args.units[1],args.units[0],(results.upload / 1000.0 / 1000.0) / args.units[1],args.units[0]))elif args.csv:printer(results.csv(delimiter=args.csv_delimiter))elif args.json:printer(results.json())if args.share and not machine_format:printer('Share results: %s' % results.share())def main():try:shell()except KeyboardInterrupt:printer('\nCancelling...', error=True)except (SpeedtestException, SystemExit):e = get_exception()# Ignore a successful exit, or argparse exitif getattr(e, 'code', 1) not in (0, 2):msg = '%s' % eif not msg:msg = '%r' % eraise SystemExit('ERROR: %s' % msg)if __name__ == '__main__':main()

网络急速诊断,快速测试网络速度相关推荐

  1. 如何快速测试网络链路质量?

    在我们日常工作.学习.上网过程中经常会遇到网络卡.慢.时断时续的现象,企业的信息中心或是网络中心经常会接到这样的投诉,那这个网络故障到底是由什么原因引起的呢?这是个非常复杂的事情,解决起来也是比较头疼 ...

  2. 怎样测网络服务器延迟,怎么测试网络延迟?

    满意答案 kerongbeng 2013.03.14 采纳率:50%    等级:11 已帮助:16535人 第一步:WIN桌面--开始--运行 第二步:输入:CMD 回车---输入PING命令:pi ...

  3. 区块链学堂(6):以太坊生产网络/测试网络/私有网络

    区块链学堂(6):以太坊生产网络/测试网络/私有网络 要理解以太坊 PrivateNetwork 先要理解以太坊的两种官方网络 目前以太坊官方提供了两种网络 生产环境网络 测试网络 TestNet 下 ...

  4. macos 虚拟镜像文件_如何在macOS中使用虚拟文件测试网络或硬盘速度

    macos 虚拟镜像文件 File transfer speeds can vary greatly from device to device. The same holds true for ne ...

  5. 如何在Windows中使用虚拟文件测试网络或硬盘速度

    If you want to see how fast your network really is, or test the speed between two hard drives, then ...

  6. 苹果手机测试网络速度的软件,‎App Store 上的“网速测试大师-测网速首选”

    网速测试大师(SpeedTest Master)致力于为全球用户提供快速专业的网络测速服务.[最新功能]5G测速.Ping 测试.游戏Ping.一键设备检测. 网速测试大师,是您的手机管家,wifi管 ...

  7. 苹果手机测试网络速度的软件,iPhone6怎么看网速?查看苹果6 Plus网速给不给力的方法...

    iPhone6怎么看网速?小伙伴们在买了当前苹果最新的 iPhone6 手机,也开了3G或4G网络,可能想查看一下当前手机的网速到底怎么样.俗话说得好,不服来跑个分.下面简单介绍下怎么在苹果 iPho ...

  8. (网络速度)电信拉的100M光纤,测试峰值速度只有12M/s

    常见问题:电信拉的100M光纤,测试峰值速度只有12M/s 这就涉及到了计算机网络中的单位. 容量单位: bit byte kb mb gb tb pb eb 宽带中的M不是容量.是指的网络速度. 例 ...

  9. JS 测试网络速度与网络延迟

    一.延迟与网速 通过js加载一张1x1的极小图片,测试出图片加载的所用的时长.如果换一个几百KB的图片,则可心用来计算下载网速 document.write('<input type=" ...

最新文章

  1. shell编程_linux
  2. Deploying Windows Mobile 6 with Exchange Server 2007 白皮书
  3. 电子到底为什么会干涉?
  4. 1.12 Java空对象(null)是怎么回事?
  5. JS导出 excel
  6. Learn python the seventh day
  7. 作业帮电脑版在线使用_互助作业帮PC版-互助作业帮电脑版下载 v4.5.8
  8. Java 8新特性(二)
  9. 选防晒霜 要看四个要点 - 健康程序员,至尚生活!
  10. PL/SQL中的=作用
  11. fast.ai 深度学习笔记:第一部分第三课
  12. 苹果全面封杀Facebook:原因不能忍
  13. mysql 周 获取日期_MySQL获取日期周、月、天,生成序号
  14. R语言相关性分析与偏相关分析
  15. sql server 2005 32位+64位、企业版+标准版、CD+DVD 下载地址大全【申明:来源于网络】
  16. 百度影音盒插入论坛帖子自动播放代码及方法
  17. 如果你的爆款产品还没有……可能即将被KO
  18. 小米10性能再进化!小米带来国内安卓系统GPU驱动首次更新——初阶GPU及其驱动升级认识
  19. 树模型(一):预备知识
  20. 每晚泡脚15分钟,5年下来有哪些变化

热门文章

  1. 2022-2028全球与中国国内和国际物流服务市场现状及未来发展趋势
  2. 如何提升公众号的阅读量?提高公众号阅读量的方法介绍
  3. 终于来了!我们发布了 PAKDD 2021 智能运维大赛 baseline
  4. VOL vs. VLK by Plod
  5. 【Git】回退 commit 版本详解
  6. 关系模式(关系模式必须遵循)
  7. matplotlib之pyplot模块——获取或设置坐标轴刻度及标签(xticks、yticks)
  8. numpy和pandas的操作
  9. Luogu P1144 最短路计数
  10. TSP问题-多种算法求解