|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
做爬虫的时候无外乎就是向目标web服务器发送http请求,然后接受响应,然后解析返回的信息,提取url,再利用获取到的url,再次提交,所以不管怎么说,url是爬虫中比较重要的部分,也是比较基础的部分,我自己感觉学爬虫首先需要懂http协议,而http中url、http请求和 响应格式是比较重要的部分,在前面这几篇中,我想把这些基础概念进行一下说明,这篇讲url,后面就分别是http请求和http的响应
url简介
url,全称是Uniform Resource Locator(统一资源定位符),它主要用来标明请求资源所在位置,它的基本格式为:
scheme://hostname[:port] / path / [;parameters][?query]#fragment,各个部分的含义如下:
scheme:表示网络传输协议,url中一般有http/https/ftp/mailto 等等,这个一般稍微了解网络的都知道,就不再详细的说下去
[list=2]
hostname:主机名,一般是一串字符串,也就是一个域名,也可以是一个IP地址,用来表示目标服务器在网络中的位置,如果是一个域名,在请求时将会由DNS服务器解析成IP地址
[list=3]
port:端口号,在url中这个值可有可无,如果没有则采用协议的默认端口号,比如http的80,ftp的21端口等等
[list=4]
path:请求资源在服务器上的位置,我们通过前面的host找到了对应的主机,加上这个文件路径,表示我们将要请求这台机器上这个位置的内容,服务器接受到请求后将目标文件返回给我们
[list=5]
parameters:这是用于指定特殊参数的可选项。这个基本上很少出现,具体怎么用,我也不太懂
[list=6]
query:请求参数,一般用于给动态网页传递参数,它一般是一个键值对,书写方式为key=value,不同键值对间使用&分割
fragment:用于指定网络资源中的片断,这样说可能不太好懂,但是这个东西说白了,我感觉它就是定位本页面的锚点(知道html的人应该都知道锚点,不知道的请自行百度)
url分绝对路径和相对路径,绝对路径就上上面的格式,有协议、域名、文件路径等等,这个一般用于请求发起方,毕竟你要请求数据,总的告诉浏览器,你要请求哪台主机,什么位置的数据。这个值在浏览器的地址栏中可以看见,而相对路径一般只有文件路径和后面的部分,它相对于这台主机上来说的,一般在解析网页时出现的比较多,为了能利用这个解析出来的url进行下次请求,我们需要将绝对路径转化为相对路径
下面看一份代码,这段代码是进行url操作的,我将一般的url操作给定义了一个类:
- import urlparse
- import re
- DEFAULT_CODINNG = "utf-8"
- class Url:
- def __init__(self, url, encoding = DEFAULT_CODINNG):
- if not re.match(r"http[s]?://", url):
- self.url = "http://" + url #默认协议是http协议
- else:
- self.url = url
- self.encoding = encoding
- urlparam = urlparse.urlparse(self.url) #使用Python自带的模块解析url
- self.protocl = urlparam.scheme
- if urlparam.port is None: #获取url中主机的端口,如果没有,则默认使用80端口
- self.port = 80
- else:
- self.port = int(urlparam.port)
- self.host = urlparam.hostname
- self.query = urlparam.query
- self.fragment = urlparam.fragment
- self.path = urlparam.path
- self.param = urlparam.params
- def getHost(self): #h获取主机名
- return self.host
- def getDomain(self): #获取域名
- return self.host
- def getPort(self): #获取端口
- return self.port
- def getPath(self): #获取url的路经
- return self.path
- def getFileName(self): #获取文件名称
- return self.path[self.path.rfind("/") + 1:]
- def getExt(self): #获取文件扩展名
- return self.path[self.path.rfind(".") + 1:]
- def getFullUrl(self):
- netloc = self.host + ":" + str(self.port)
- data = (self.protocl, netloc, self.path, self.param, self.query, self.fragment)
- _url = urlparse.urlunparse(data)
- un_url = ""
- try:
- un_url = unicode(_url)
- except UnicodeDecodeError, e:
- un_url = unicode(_url, self.encoding, "replace")
- return un_url
- def getQueryString(self):
- return self.query
- def __str__(self):
- return self.getFullUrl()
- if __name__ == '__main__':
- url = Url("http://www.anquanbao.com/book/index.php?id=1#top")
- print url.getDomain()
- print url.getExt()
- print url.getFileName()
- print url.getFullUrl()
- print url.getHost()
- print url.getPath()
- print url.getPort()
- print url.getQueryString()
复制代码
这段代码演示了如何解析url的各个部分,并且将url的各个部分拼接成一个完成的url字符串,其实在python中自带的urlparse是一个十分优秀的模块,基本涵盖了url的所有操作,在这提供这段代码主要是为了演示url各个部分的含义,我自己感觉这段使用价值不高。
最后在看一个比较麻烦的问题——url编码问题:
在爬取页面的时候可能会出现url中带有中文,这个时候就需要进行编码的转化,在转化时具体的编码规则我不是太清楚,在使用Python时一般都是将其转化为utf-8编码,然后再调用urllib库中的的函数unquote来进行转化。我们利用这个方法对含有中文的url进行转化:在上面的类中添加这样的代码:
- def urlEncoding(self):
- url_en = self.getFullUrl().encode("utf-8")
- url_en = urllib.quote(url_en)
- return url_en
复制代码
上述代码首先将传入的url转化为Unicode字符串,然后转化为utf-8,接着调用quote函数进行编码,一切都是这么顺理成章,但是我们使用一个带有中文的部分进行测试后发现,它将"http://www.baidu.com?query=测试url:转化成了"http%3A//www.baidu.com%3A80%3Fquery%3D%E6%B5%8B%E8%AF%95url",原来在url中,各个部分除了不能出现中文,还有诸如“:”等一些特殊字符,但是在url中需要它作为格式的区分,函数将它整个进行了转化,既然不能对整体进行转化,那么我们就对各个部分进行转化其实函数quote只需要传入一个字符串,这个字符串不需要满足url的格式,所以,现在又有了一个新的思路,我们使用urlparse将url分成各个部分,然后针对各个部分调用quote转化,最后将它们拼接起来就成了一个完整的url,下面是具体的代码:
- def urlEncoding(self):
- #默认scheme、host、port这个几个部分没有中文
- #编码path
- path_en = self.path
- if self.path == "":
- path_en = unicode(self.path, self.encoding, "replace")
- path_en = path_en.encode('utf-8')
- path_en = urllib.quote(path_en)
- #编码fragment
- fragment_en = self.fragment
- if self.fragment != "":
- fragment_en = unicode(self.fragment, self.encoding, "replace")
- fragment_en = fragment_en.encode('utf-8')
- fragment_en = urllib.quote(fragment_en)
- query_en = self.query
- if self.query != "":
- query_en = ""
- query_dict = urlparse.parse_qs(self.query)
- for k, v in query_dict.iteritems():
- k_en = unicode(k, self.encoding, "replace")
- k_en = k_en.encode('utf-8')
- k_en = urllib.quote(k_en)
- value_en = v[0]
- value_en = unicode(value_en, self.encoding, "replace")
- value_en = value_en.encode('utf-8')
- value_en = urllib.quote(value_en)
- query_en = query_en + k_en + "=" + value_en + "&"
- query_list = list(query_en)
- if query_list[-1] == "&":
- query_list.pop()
- query_en = "".join(query_list)
- netloc = self.host + ":" + str(self.port)
- _url = self.protocl + "://" + netloc
- if self.param != "":
- _url += ";" + self.param
- _url += path_en
- if self.query != "":
- _url += "?" + query_en
- if self.fragment != "":
- _url += "#" + fragment_en
- return _url
复制代码
将这个函数加入到类中,这样就可以进行url的编码,当然在这,异常处理可能不够,毕竟编码问题是最让人头疼的,还有就是我默认向协议、主机、端口、参数这些地方不会出现特殊字符,但是具体是不是这样我也不太清楚,还是那句话,这些代码只是给大家做一个参考。
好了,url的部分就说到这,下一篇将进行http请求的说明,敬请期待。。。。
|
评分
-
查看全部评分
|