Python之网络爬虫完全教程


原文传送门:http://blog.csdn.net/column/details/why-bug.html

[Python]网络爬虫(一):抓取网页的含义和URL基本构成

一、网络爬虫的定义

网络爬虫,即Web Spider,是一个很形象的名字。

把互联网比喻成一个蜘蛛网,那么Spider就是在网上爬来爬去的蜘蛛。
网络蜘蛛是通过网页的链接地址来寻找网页的。

从网站某一个页面(通常是首页)开始,读取网页的内容,找到在网页中的其它链接地址,

然后通过这些链接地址寻找下一个网页,这样一直循环下去,直到把这个网站所有的网页都抓取完为止。

如果把整个互联网当成一个网站,那么网络蜘蛛就可以用这个原理把互联网上所有的网页都抓取下来。

这样看来,网络爬虫就是一个爬行程序,一个抓取网页的程序。

网络爬虫的基本操作是抓取网页。

那么如何才能随心所欲地获得自己想要的页面?

我们先从URL开始。


二、浏览网页的过程

抓取网页的过程其实和读者平时使用IE浏览器浏览网页的道理是一样的。

比如说你在浏览器的地址栏中输入    www.baidu.com    这个地址。

打开网页的过程其实就是浏览器作为一个浏览的“客户端”,向服务器端发送了 一次请求,把服务器端的文件“抓”到本地,再进行解释、展现。

HTML是一种标记语言,用标签标记内容并加以解析和区分。

浏览器的功能是将获取到的HTML代码进行解析,然后将原始的代码转变成我们直接看到的网站页面。


三、URI和URL的概念和举例

简单的来讲,URL就是在浏览器端输入的    http://www.baidu.com    这个字符串。

在理解URL之前,首先要理解URI的概念。

什么是URI?

Web上每种可用的资源,如 HTML文档、图像、视频片段、程序等都由一个通用资源标志符(Universal Resource Identifier, URI)进行定位。 

URI通常由三部分组成:

①访问资源的命名机制;

②存放资源的主机名;

③资源自身 的名称,由路径表示。

如下面的URI:
http://www.why.com.cn/myhtml/html1223/

我们可以这样解释它:

①这是一个可以通过HTTP协议访问的资源,

②位于主机 www.webmonkey.com.cn上,

③通过路径“/html/html40”访问。 


四、URL的理解和举例

URL是URI的一个子集。它是Uniform Resource Locator的缩写,译为“统一资源定位 符”。

通俗地说,URL是Internet上描述信息资源的字符串,主要用在各种WWW客户程序和服务器程序上。

采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。

URL的一般格式为(带方括号[]的为可选项):

protocol :// hostname[:port] / path / [;parameters][?query]#fragment


URL的格式由三部分组成: 

①第一部分是协议(或称为服务方式)。

②第二部分是存有该资源的主机IP地址(有时也包括端口号)。

③第三部分是主机资源的具体地址,如目录和文件名等。

第一部分和第二部分用“://”符号隔开,

第二部分和第三部分用“/”符号隔开。

第一部分和第二部分是不可缺少的,第三部分有时可以省略。 


五、URL和URI简单比较

URI属于URL更低层次的抽象,一种字符串文本标准。

换句话说,URI属于父类,而URL属于URI的子类。URL是URI的一个子集。

URI的定义是:统一资源标识符;

URL的定义是:统一资源定位符。

二者的区别在于,URI表示请求服务器的路径,定义这么一个资源。

而URL同时说明要如何访问这个资源(http://)。





下面来看看两个URL的小例子。


1.HTTP协议的URL示例:
使用超级文本传输协议HTTP,提供超级文本信息服务的资源。 

例:http://www.peopledaily.com.cn/channel/welcome.htm 

其计算机域名为www.peopledaily.com.cn。

超级文本文件(文件类型为.html)是在目录 /channel下的welcome.htm。

这是中国人民日报的一台计算机。 

例:http://www.rol.cn.net/talk/talk1.htm 

其计算机域名为www.rol.cn.net。

超级文本文件(文件类型为.html)是在目录/talk下的talk1.htm。

这是瑞得聊天室的地址,可由此进入瑞得聊天室的第1室。


2.文件的URL
用URL表示文件时,服务器方式用file表示,后面要有主机IP地址、文件的存取路 径(即目录)和文件名等信息。

有时可以省略目录和文件名,但“/”符号不能省略。 

例:file://ftp.yoyodyne.com/pub/files/foobar.txt 

上面这个URL代表存放在主机ftp.yoyodyne.com上的pub/files/目录下的一个文件,文件名是foobar.txt。

例:file://ftp.yoyodyne.com/pub 

代表主机ftp.yoyodyne.com上的目录/pub。 

例:file://ftp.yoyodyne.com/ 

代表主机ftp.yoyodyne.com的根目录。 


爬虫最主要的处理对象就是URL,它根据URL地址取得所需要的文件内容,然后对它 进行进一步的处理。

因此,准确地理解URL对理解网络爬虫至关重要。


[Python]网络爬虫(二):利用urllib2通过指定的URL抓取网页内容

版本号:Python2.7.5,Python3改动较大,各位另寻教程。

所谓网页抓取,就是把URL地址中指定的网络资源从网络流中读取出来,保存到本地。 
类似于使用程序模拟IE浏览器的功能,把URL作为HTTP请求的内容发送到服务器端, 然后读取服务器端的响应资源。


在Python中,我们使用urllib2这个组件来抓取网页。
urllib2是Python的一个获取URLs(Uniform Resource Locators)的组件。

它以urlopen函数的形式提供了一个非常简单的接口。

最简单的urllib2的应用代码只需要四行。

我们新建一个文件urllib2_test01.py来感受一下urllib2的作用:

[python]  view plain copy
  1. import urllib2  
  2. response = urllib2.urlopen('http://www.baidu.com/')  
  3. html = response.read()  
  4. print html  

按下F5可以看到运行的结果:

Python之网络爬虫完全教程_第1张图片

我们可以打开百度主页,右击,选择查看源代码(火狐OR谷歌浏览器均可),会发现也是完全一样的内容。

也就是说,上面这四行代码将我们访问百度时浏览器收到的代码们全部打印了出来。

这就是一个最简单的urllib2的例子。


除了"http:",URL同样可以使用"ftp:","file:"等等来替代。

HTTP是基于请求和应答机制的:

客户端提出请求,服务端提供应答。


urllib2用一个Request对象来映射你提出的HTTP请求。

在它最简单的使用形式中你将用你要请求的地址创建一个Request对象,

通过调用urlopen并传入Request对象,将返回一个相关请求response对象,

这个应答对象如同一个文件对象,所以你可以在Response中调用.read()。

我们新建一个文件urllib2_test02.py来感受一下:

[python]  view plain copy
  1. import urllib2    
  2. req = urllib2.Request('http://www.baidu.com')    
  3. response = urllib2.urlopen(req)    
  4. the_page = response.read()    
  5. print the_page  

可以看到输出的内容和test01是一样的。

urllib2使用相同的接口处理所有的URL头。例如你可以像下面那样创建一个ftp请求。

[python]  view plain copy
  1. req = urllib2.Request('ftp://example.com/')  
在HTTP请求时,允许你做额外的两件事。

1.发送data表单数据

这个内容相信做过Web端的都不会陌生,

有时候你希望发送一些数据到URL(通常URL与CGI[通用网关接口]脚本,或其他WEB应用程序挂接)。

在HTTP中,这个经常使用熟知的POST请求发送。

这个通常在你提交一个HTML表单时由你的浏览器来做。

并不是所有的POSTs都来源于表单,你能够使用POST提交任意的数据到你自己的程序。

一般的HTML表单,data需要编码成标准形式。然后做为data参数传到Request对象。

编码工作使用urllib的函数而非urllib2。

我们新建一个文件urllib2_test03.py来感受一下:

[python]  view plain copy
  1. import urllib    
  2. import urllib2    
  3.   
  4. url = 'http://www.someserver.com/register.cgi'    
  5.     
  6. values = {'name' : 'WHY',    
  7.           'location' : 'SDU',    
  8.           'language' : 'Python' }    
  9.   
  10. data = urllib.urlencode(values) # 编码工作  
  11. req = urllib2.Request(url, data)  # 发送请求同时传data表单  
  12. response = urllib2.urlopen(req)  #接受反馈的信息  
  13. the_page = response.read()  #读取反馈的内容  

如果没有传送data参数,urllib2使用GET方式的请求。

GET和POST请求的不同之处是POST请求通常有"副作用",

它们会由于某种途径改变系统状态(例如提交成堆垃圾到你的门口)。

Data同样可以通过在Get请求的URL本身上面编码来传送。

[python]  view plain copy
  1. import urllib2    
  2. import urllib  
  3.   
  4. data = {}  
  5.   
  6. data['name'] = 'WHY'    
  7. data['location'] = 'SDU'    
  8. data['language'] = 'Python'  
  9.   
  10. url_values = urllib.urlencode(data)    
  11. print url_values  
  12.   
  13. name=Somebody+Here&language=Python&location=Northampton    
  14. url = 'http://www.example.com/example.cgi'    
  15. full_url = url + '?' + url_values  
  16.   
  17. data = urllib2.open(full_url)    

这样就实现了Data数据的Get传送。


2.设置Headers到http请求

有一些站点不喜欢被程序(非人为访问)访问,或者发送不同版本的内容到不同的浏览器。

默认的urllib2把自己作为“Python-urllib/x.y”(x和y是Python主版本和次版本号,例如Python-urllib/2.7),

这个身份可能会让站点迷惑,或者干脆不工作。

浏览器确认自己身份是通过User-Agent头,当你创建了一个请求对象,你可以给他一个包含头数据的字典。

下面的例子发送跟上面一样的内容,但把自身模拟成Internet Explorer。

(多谢大家的提醒,现在这个Demo已经不可用了,不过原理还是那样的)。

[python]  view plain copy
  1. import urllib    
  2. import urllib2    
  3.   
  4. url = 'http://www.someserver.com/cgi-bin/register.cgi'  
  5.   
  6. user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'    
  7. values = {'name' : 'WHY',    
  8.           'location' : 'SDU',    
  9.           'language' : 'Python' }    
  10.   
  11. headers = { 'User-Agent' : user_agent }    
  12. data = urllib.urlencode(values)    
  13. req = urllib2.Request(url, data, headers)    
  14. response = urllib2.urlopen(req)    
  15. the_page = response.read()   
[Python]网络爬虫(三):异常的处理和HTTP状态码的分类

先来说一说HTTP的异常处理问题。
当urlopen不能够处理一个response时,产生urlError。
不过通常的Python APIs异常如ValueError,TypeError等也会同时产生。
HTTPError是urlError的子类,通常在特定HTTP URLs中产生。
 
1.URLError
通常,URLError在没有网络连接(没有路由到特定服务器),或者服务器不存在的情况下产生。

这种情况下,异常同样会带有"reason"属性,它是一个tuple(可以理解为不可变的数组),

包含了一个错误号和一个错误信息。

我们建一个urllib2_test06.py来感受一下异常的处理:

[python]  view plain copy
  1. import urllib2  
  2.   
  3. req = urllib2.Request('http://www.baibai.com')  
  4.   
  5. try: urllib2.urlopen(req)  
  6.   
  7. except urllib2.URLError, e:    
  8.     print e.reason  


按下F5,可以看到打印出来的内容是:

[Errno 11001] getaddrinfo failed

也就是说,错误号是11001,内容是getaddrinfo failed


2.HTTPError
服务器上每一个HTTP 应答对象response包含一个数字"状态码"。

有时状态码指出服务器无法完成请求。默认的处理器会为你处理一部分这种应答。

例如:假如response是一个"重定向",需要客户端从别的地址获取文档,urllib2将为你处理。

其他不能处理的,urlopen会产生一个HTTPError。

典型的错误包含"404"(页面无法找到),"403"(请求禁止),和"401"(带验证请求)。

HTTP状态码表示HTTP协议所返回的响应的状态。

比如客户端向服务器发送请求,如果成功地获得请求的资源,则返回的状态码为200,表示响应成功。

如果请求的资源不存在, 则通常返回404错误。 

HTTP状态码通常分为5种类型,分别以1~5五个数字开头,由3位整数组成:

------------------------------------------------------------------------------------------------

200:请求成功      处理方式:获得响应的内容,进行处理 

201:请求完成,结果是创建了新资源。新创建资源的URI可在响应的实体中得到    处理方式:爬虫中不会遇到 

202:请求被接受,但处理尚未完成    处理方式:阻塞等待 

204:服务器端已经实现了请求,但是没有返回新的信 息。如果客户是用户代理,则无须为此更新自身的文档视图。    处理方式:丢弃

300:该状态码不被HTTP/1.0的应用程序直接使用, 只是作为3XX类型回应的默认解释。存在多个可用的被请求资源。    处理方式:若程序中能够处理,则进行进一步处理,如果程序中不能处理,则丢弃
301:请求到的资源都会分配一个永久的URL,这样就可以在将来通过该URL来访问此资源    处理方式:重定向到分配的URL
302:请求到的资源在一个不同的URL处临时保存     处理方式:重定向到临时的URL 

304 请求的资源未更新     处理方式:丢弃 

400 非法请求     处理方式:丢弃 

401 未授权     处理方式:丢弃 

403 禁止     处理方式:丢弃 

404 没有找到     处理方式:丢弃 

5XX 回应代码以“5”开头的状态码表示服务器端发现自己出现错误,不能继续执行请求    处理方式:丢弃

------------------------------------------------------------------------------------------------

HTTPError实例产生后会有一个整型'code'属性,是服务器发送的相关错误号。

Error Codes错误码
因为默认的处理器处理了重定向(300以外号码),并且100-299范围的号码指示成功,所以你只能看到400-599的错误号码。
BaseHTTPServer.BaseHTTPRequestHandler.response是一个很有用的应答号码字典,显示了HTTP协议使用的所有的应答号。

当一个错误号产生后,服务器返回一个HTTP错误号,和一个错误页面。

你可以使用HTTPError实例作为页面返回的应答对象response。

这表示和错误属性一样,它同样包含了read,geturl,和info方法。

我们建一个urllib2_test07.py来感受一下:

[python]  view plain copy
  1. import urllib2  
  2. req = urllib2.Request('http://bbs.csdn.net/callmewhy')  
  3.   
  4. try:  
  5.     urllib2.urlopen(req)  
  6.   
  7. except urllib2.URLError, e:  
  8.   
  9.     print e.code  
  10.     #print e.read()  

按下F5可以看见输出了404的错误码,也就说没有找到这个页面。



3.Wrapping

所以如果你想为HTTPError或URLError做准备,将有两个基本的办法。推荐使用第二种。

我们建一个urllib2_test08.py来示范一下第一种异常处理的方案:

[python]  view plain copy
  1. from urllib2 import Request, urlopen, URLError, HTTPError  
  2.   
  3. req = Request('http://bbs.csdn.net/callmewhy')  
  4.   
  5. try:  
  6.   
  7.     response = urlopen(req)  
  8.   
  9. except HTTPError, e:  
  10.   
  11.     print 'The server couldn\'t fulfill the request.'  
  12.   
  13.     print 'Error code: ', e.code  
  14.   
  15. except URLError, e:  
  16.   
  17.     print 'We failed to reach a server.'  
  18.   
  19.     print 'Reason: ', e.reason  
  20.   
  21. else:  
  22.     print 'No exception was raised.'  
  23.     # everything is fine  

和其他语言相似,try之后捕获异常并且将其内容打印出来。
这里要注意的一点,except HTTPError 必须在第一个,否则except URLError将同样接受到HTTPError 
因为HTTPError是URLError的子类,如果URLError在前面它会捕捉到所有的URLError(包括HTTPError )。


我们建一个urllib2_test09.py来示范一下第二种异常处理的方案:

[python]  view plain copy
  1. from urllib2 import Request, urlopen, URLError, HTTPError  
  2.   
  3. req = Request('http://bbs.csdn.net/callmewhy')  
  4.     
  5. try:    
  6.     
  7.     response = urlopen(req)    
  8.     
  9. except URLError, e:    
  10.     
  11.     if hasattr(e, 'reason'):    
  12.     
  13.         print 'We failed to reach a server.'    
  14.     
  15.         print 'Reason: ', e.reason    
  16.     
  17.     elif hasattr(e, 'code'):    
  18.     
  19.         print 'The server couldn\'t fulfill the request.'    
  20.     
  21.         print 'Error code: ', e.code    
  22.     
  23. else:    
  24.     print 'No exception was raised.'    
  25.     # everything is fine    
[Python]网络爬虫(四):Opener与Handler的介绍和实例应用

在开始后面的内容之前,先来解释一下urllib2中的两个个方法:info and geturl 

urlopen返回的应答对象response(或者HTTPError实例)有两个很有用的方法info()和geturl()

1.geturl():

这个返回获取的真实的URL,这个很有用,因为urlopen(或者opener对象使用的)或许会有重定向。获取的URL或许跟请求URL不同。

以人人中的一个超级链接为例,

我们建一个urllib2_test10.py来比较一下原始URL和重定向的链接

[python]  view plain copy
  1. from urllib2 import Request, urlopen, URLError, HTTPError  
  2.   
  3.   
  4. old_url = 'http://rrurl.cn/b1UZuP'  
  5. req = Request(old_url)  
  6. response = urlopen(req)    
  7. print 'Old url :' + old_url  
  8. print 'Real url :' + response.geturl()  
运行之后可以看到真正的链接指向的网址:

Python之网络爬虫完全教程_第2张图片

2.info():

这个返回对象的字典对象,该字典描述了获取的页面情况。通常是服务器发送的特定头headers。目前是httplib.HTTPMessage 实例。

经典的headers包含"Content-length","Content-type",和其他内容。

我们建一个urllib2_test11.py来测试一下info的应用:

[python]  view plain copy
  1. from urllib2 import Request, urlopen, URLError, HTTPError  
  2.   
  3. old_url = 'http://www.baidu.com'  
  4. req = Request(old_url)  
  5. response = urlopen(req)    
  6. print 'Info():'  
  7. print response.info()  
运行的结果如下,可以看到页面的相关信息:

Python之网络爬虫完全教程_第3张图片


下面来说一说urllib2中的两个重要概念:Openers和Handlers。

1.Openers:

当你获取一个URL你使用一个opener(一个urllib2.OpenerDirector的实例)。

正常情况下,我们使用默认opener:通过urlopen。

但你能够创建个性的openers。

2.Handles:

Openers使用处理器handlers,所有的“繁重”工作由handlers处理。

每个handlers知道如何通过特定协议打开URLs,或者如何处理URL打开时的各个方面。

例如HTTP重定向或者HTTP cookies。


如果你希望用特定处理器获取URLs你会想创建一个openers,例如获取一个能处理cookie的opener,或者获取一个不重定向的opener。


要创建一个 opener,可以实例化一个OpenerDirector,

然后调用.add_handler(some_handler_instance)。

同样,可以使用build_opener,这是一个更加方便的函数,用来创建opener对象,他只需要一次函数调用。
build_opener默认添加几个处理器,但提供快捷的方法来添加或更新默认处理器。

其他的处理器handlers你或许会希望处理代理,验证,和其他常用但有点特殊的情况。


install_opener 用来创建(全局)默认opener。这个表示调用urlopen将使用你安装的opener。

Opener对象有一个open方法。

该方法可以像urlopen函数那样直接用来获取urls:通常不必调用install_opener,除了为了方便。


说完了上面两个内容,下面我们来看一下基本认证的内容,这里会用到上面提及的Opener和Handler。

Basic Authentication 基本验证

为了展示创建和安装一个handler,我们将使用HTTPBasicAuthHandler。

当需要基础验证时,服务器发送一个header(401错误码) 请求验证。这个指定了scheme 和一个‘realm’,看起来像这样:Www-authenticate: SCHEME realm="REALM".

例如
Www-authenticate: Basic realm="cPanel Users"

客户端必须使用新的请求,并在请求头里包含正确的姓名和密码。

这是“基础验证”,为了简化这个过程,我们可以创建一个HTTPBasicAuthHandler的实例,并让opener使用这个handler就可以啦。


HTTPBasicAuthHandler使用一个密码管理的对象来处理URLs和realms来映射用户名和密码。

如果你知道realm(从服务器发送来的头里)是什么,你就能使用HTTPPasswordMgr。


通常人们不关心realm是什么。那样的话,就能用方便的HTTPPasswordMgrWithDefaultRealm。

这个将在你为URL指定一个默认的用户名和密码。

这将在你为特定realm提供一个其他组合时得到提供。

我们通过给realm参数指定None提供给add_password来指示这种情况。


最高层次的URL是第一个要求验证的URL。你传给.add_password()更深层次的URLs将同样合适。

说了这么多废话,下面来用一个例子演示一下上面说到的内容。

我们建一个urllib2_test12.py来测试一下info的应用:

[python]  view plain copy
  1. # -*- coding: utf-8 -*-  
  2. import urllib2  
  3.   
  4. # 创建一个密码管理者  
  5. password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()  
  6.   
  7. # 添加用户名和密码  
  8.   
  9. top_level_url = "http://example.com/foo/"  
  10.   
  11. # 如果知道 realm, 我们可以使用他代替 ``None``.  
  12. # password_mgr.add_password(None, top_level_url, username, password)  
  13. password_mgr.add_password(None, top_level_url,'why''1223')  
  14.   
  15. # 创建了一个新的handler  
  16. handler = urllib2.HTTPBasicAuthHandler(password_mgr)  
  17.   
  18. # 创建 "opener" (OpenerDirector 实例)  
  19. opener = urllib2.build_opener(handler)  
  20.   
  21. a_url = 'http://www.baidu.com/'  
  22.   
  23. # 使用 opener 获取一个URL  
  24. opener.open(a_url)  
  25.   
  26. # 安装 opener.  
  27. # 现在所有调用 urllib2.urlopen 将用我们的 opener.  
  28. urllib2.install_opener(opener)  
  29.   
  30.    

注意:以上的例子我们仅仅提供我们的HHTPBasicAuthHandler给build_opener。

默认的openers有正常状况的handlers:ProxyHandler,UnknownHandler,HTTPHandler,HTTPDefaultErrorHandler, HTTPRedirectHandler,FTPHandler, FileHandler, HTTPErrorProcessor。

代码中的top_level_url 实际上可以是完整URL(包含"http:",以及主机名及可选的端口号)。

例如:http://example.com/。

也可以是一个“authority”(即主机名和可选的包含端口号)。

例如:“example.com” or “example.com:8080”。

后者包含了端口号。


[Python]网络爬虫(五):urllib2的使用细节与抓站技巧

前面说到了urllib2的简单入门,下面整理了一部分urllib2的使用细节。


1.Proxy 的设置

urllib2 默认会使用环境变量 http_proxy 来设置 HTTP Proxy。

如果想在程序中明确控制 Proxy 而不受环境变量的影响,可以使用代理。

新建test14来实现一个简单的代理Demo:

[python]  view plain copy
  1. import urllib2  
  2. enable_proxy = True  
  3. proxy_handler = urllib2.ProxyHandler({"http" : 'http://some-proxy.com:8080'})  
  4. null_proxy_handler = urllib2.ProxyHandler({})  
  5. if enable_proxy:  
  6.     opener = urllib2.build_opener(proxy_handler)  
  7. else:  
  8.     opener = urllib2.build_opener(null_proxy_handler)  
  9. urllib2.install_opener(opener)  

这里要注意的一个细节,使用 urllib2.install_opener() 会设置 urllib2 的全局 opener 。

这样后面的使用会很方便,但不能做更细致的控制,比如想在程序中使用两个不同的 Proxy 设置等。

比较好的做法是不使用 install_opener 去更改全局的设置,而只是直接调用 opener 的 open 方法代替全局的 urlopen 方法。


2.Timeout 设置
在老版 Python 中(Python2.6前),urllib2 的 API 并没有暴露 Timeout 的设置,要设置 Timeout 值,只能更改 Socket 的全局 Timeout 值。
[python]  view plain copy
  1. import urllib2  
  2. import socket  
  3. socket.setdefaulttimeout(10# 10 秒钟后超时  
  4. urllib2.socket.setdefaulttimeout(10# 另一种方式  

在 Python 2.6 以后,超时可以通过 urllib2.urlopen() 的 timeout 参数直接设置。
[python]  view plain copy
  1. import urllib2  
  2. response = urllib2.urlopen('http://www.google.com', timeout=10)  


3.在 HTTP Request 中加入特定的 Header

要加入 header,需要使用 Request 对象:
[python]  view plain copy
  1. import urllib2  
  2. request = urllib2.Request('http://www.baidu.com/')  
  3. request.add_header('User-Agent''fake-client')  
  4. response = urllib2.urlopen(request)  
  5. print response.read()  

对有些 header 要特别留意,服务器会针对这些 header 做检查
User-Agent : 有些服务器或 Proxy 会通过该值来判断是否是浏览器发出的请求
Content-Type : 在使用 REST 接口时,服务器会检查该值,用来确定 HTTP Body 中的内容该怎样解析。常见的取值有:
application/xml : 在 XML RPC,如 RESTful/SOAP 调用时使用
application/json : 在 JSON RPC 调用时使用
application/x-www-form-urlencoded : 浏览器提交 Web 表单时使用
在使用服务器提供的 RESTful 或 SOAP 服务时, Content-Type 设置错误会导致服务器拒绝服务



4.Redirect
urllib2 默认情况下会针对 HTTP 3XX 返回码自动进行 redirect 动作,无需人工配置。要检测是否发生了 redirect 动作,只要检查一下 Response 的 URL 和 Request 的 URL 是否一致就可以了。
[python]  view plain copy
  1. import urllib2  
  2. my_url = 'http://www.google.cn'  
  3. response = urllib2.urlopen(my_url)  
  4. redirected = response.geturl() == my_url  
  5. print redirected  
  6.   
  7. my_url = 'http://rrurl.cn/b1UZuP'  
  8. response = urllib2.urlopen(my_url)  
  9. redirected = response.geturl() == my_url  
  10. print redirected  

如果不想自动 redirect,除了使用更低层次的 httplib 库之外,还可以自定义HTTPRedirectHandler 类。
[python]  view plain copy
  1. import urllib2  
  2. class RedirectHandler(urllib2.HTTPRedirectHandler):  
  3.     def http_error_301(self, req, fp, code, msg, headers):  
  4.         print "301"  
  5.         pass  
  6.     def http_error_302(self, req, fp, code, msg, headers):  
  7.         print "303"  
  8.         pass  
  9.   
  10. opener = urllib2.build_opener(RedirectHandler)  
  11. opener.open('http://rrurl.cn/b1UZuP')  


5.Cookie

urllib2 对 Cookie 的处理也是自动的。如果需要得到某个 Cookie 项的值,可以这么做:
[python]  view plain copy
  1. import urllib2  
  2. import cookielib  
  3. cookie = cookielib.CookieJar()  
  4. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))  
  5. response = opener.open('http://www.baidu.com')  
  6. for item in cookie:  
  7.     print 'Name = '+item.name  
  8.     print 'Value = '+item.value  

运行之后就会输出访问百度的Cookie值:

Python之网络爬虫完全教程_第4张图片


6.使用 HTTP 的 PUT 和 DELETE 方法

urllib2 只支持 HTTP 的 GET 和 POST 方法,如果要使用 HTTP PUT 和 DELETE ,只能使用比较低层的 httplib 库。虽然如此,我们还是能通过下面的方式,使 urllib2 能够发出 PUT 或DELETE 的请求:
[python]  view plain copy
  1. import urllib2  
  2. request = urllib2.Request(uri, data=data)  
  3. request.get_method = lambda'PUT' # or 'DELETE'  
  4. response = urllib2.urlopen(request)  


7.得到 HTTP 的返回码

对于 200 OK 来说,只要使用 urlopen 返回的 response 对象的 getcode() 方法就可以得到 HTTP 的返回码。但对其它返回码来说,urlopen 会抛出异常。这时候,就要检查异常对象的 code 属性了:
[python]  view plain copy
  1. import urllib2  
  2. try:  
  3.     response = urllib2.urlopen('http://bbs.csdn.net/why')  
  4. except urllib2.HTTPError, e:  
  5.     print e.code  


8.Debug Log

使用 urllib2 时,可以通过下面的方法把 debug Log 打开,这样收发包的内容就会在屏幕上打印出来,方便调试,有时可以省去抓包的工作
[python]  view plain copy
  1. import urllib2  
  2. httpHandler = urllib2.HTTPHandler(debuglevel=1)  
  3. httpsHandler = urllib2.HTTPSHandler(debuglevel=1)  
  4. opener = urllib2.build_opener(httpHandler, httpsHandler)  
  5. urllib2.install_opener(opener)  
  6. response = urllib2.urlopen('http://www.google.com')  

这样就可以看到传输的数据包内容了:

Python之网络爬虫完全教程_第5张图片



9.表单的处理

登录必要填表,表单怎么填?

首先利用工具截取所要填表的内容。
比如我一般用firefox+httpfox插件来看看自己到底发送了些什么包。
以verycd为例,先找到自己发的POST请求,以及POST表单项。
可以看到verycd的话需要填username,password,continueURI,fk,login_submit这几项,其中fk是随机生成的(其实不太随机,看上去像是把epoch时间经过简单的编码生成的),需要从网页获取,也就是说得先访问一次网页,用正则表达式等工具截取返回数据中的fk项。continueURI顾名思义可以随便写,login_submit是固定的,这从源码可以看出。还有username,password那就很显然了:

[python]  view plain copy
  1. # -*- coding: utf-8 -*-  
  2. import urllib  
  3. import urllib2  
  4. postdata=urllib.urlencode({  
  5.     'username':'汪小光',  
  6.     'password':'why888',  
  7.     'continueURI':'http://www.verycd.com/',  
  8.     'fk':'',  
  9.     'login_submit':'登录'  
  10. })  
  11. req = urllib2.Request(  
  12.     url = 'http://secure.verycd.com/signin',  
  13.     data = postdata  
  14. )  
  15. result = urllib2.urlopen(req)  
  16. print result.read()   


10.伪装成浏览器访问
某些网站反感爬虫的到访,于是对爬虫一律拒绝请求
这时候我们需要伪装成浏览器,这可以通过修改http包中的header来实现

[python]  view plain copy
  1. #…  
  2.   
  3. headers = {  
  4.     'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'  
  5. }  
  6. req = urllib2.Request(  
  7.     url = 'http://secure.verycd.com/signin/*/http://www.verycd.com/',  
  8.     data = postdata,  
  9.     headers = headers  
  10. )  
  11. #...  

11.对付"反盗链"
某些站点有所谓的反盗链设置,其实说穿了很简单,

就是检查你发送请求的header里面,referer站点是不是他自己,

所以我们只需要像把headers的referer改成该网站即可,以cnbeta为例:

#...
headers = {
    'Referer':'http://www.cnbeta.com/articles'
}
#...

headers是一个dict数据结构,你可以放入任何想要的header,来做一些伪装。

例如,有些网站喜欢读取header中的X-Forwarded-For来看看人家的真实IP,可以直接把X-Forwarde-For改了。



[Python]网络爬虫(六):一个简单的百度贴吧的小爬虫


[python]  view plain copy
  1. # -*- coding: utf-8 -*-  
  2. #---------------------------------------  
  3. #   程序:百度贴吧爬虫  
  4. #   版本:0.1  
  5. #   作者:why  
  6. #   日期:2013-05-14  
  7. #   语言:Python 2.7  
  8. #   操作:输入带分页的地址,去掉最后面的数字,设置一下起始页数和终点页数。  
  9. #   功能:下载对应页码内的所有页面并存储为html文件。  
  10. #---------------------------------------  
  11.    
  12. import string, urllib2  
  13.    
  14. #定义百度函数  
  15. def baidu_tieba(url,begin_page,end_page):     
  16.     for i in range(begin_page, end_page+1):  
  17.         sName = string.zfill(i,5) + '.html'#自动填充成六位的文件名  
  18.         print '正在下载第' + str(i) + '个网页,并将其存储为' + sName + '......'  
  19.         f = open(sName,'w+')  
  20.         m = urllib2.urlopen(url + str(i)).read()  
  21.         f.write(m)  
  22.         f.close()  
  23.    
  24.    
  25. #-------- 在这里输入参数 ------------------  
  26.   
  27. # 这个是山东大学的百度贴吧中某一个帖子的地址  
  28. #bdurl = 'http://tieba.baidu.com/p/2296017831?pn='  
  29. #iPostBegin = 1  
  30. #iPostEnd = 10  
  31.   
  32. bdurl = str(raw_input(u'请输入贴吧的地址,去掉pn=后面的数字:\n'))  
  33. begin_page = int(raw_input(u'请输入开始的页数:\n'))  
  34. end_page = int(raw_input(u'请输入终点的页数:\n'))  
  35. #-------- 在这里输入参数 ------------------  
  36.    
  37.   
  38. #调用  
  39. baidu_tieba(bdurl,begin_page,end_page)  
[Python]网络爬虫(七):Python中的正则表达式教程


接下来准备用糗百做一个爬虫的小例子。

但是在这之前,先详细的整理一下Python中的正则表达式的相关内容。

正则表达式在Python爬虫中的作用就像是老师点名时用的花名册一样,是必不可少的神兵利器。


以下内容转自CNBLOG:http://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html

整理时没有注意,实在抱歉。


一、 正则表达式基础

1.1.概念介绍

正则表达式是用于处理字符串的强大工具,它并不是Python的一部分。

其他编程语言中也有正则表达式的概念,区别只在于不同的编程语言实现支持的语法数量不同。

它拥有自己独特的语法以及一个独立的处理引擎,在提供了正则表达式的语言里,正则表达式的语法都是一样的。

下图展示了使用正则表达式进行匹配的流程:

Python之网络爬虫完全教程_第6张图片

正则表达式的大致匹配过程是:

1.依次拿出表达式和文本中的字符比较,

2.如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。

3.如果表达式中有量词或边界,这个过程会稍微有一些不同。

下图列出了Python支持的正则表达式元字符和语法:   

Python之网络爬虫完全教程_第7张图片


1.2. 数量词的贪婪模式与非贪婪模式

正则表达式通常用于在文本中查找匹配的字符串。

贪婪模式,总是尝试匹配尽可能多的字符;

非贪婪模式则相反,总是尝试匹配尽可能少的字符。

Python里数量词默认是贪婪的。

例如:正则表达式"ab*"如果用于查找"abbbc",将找到"abbb"。

而如果使用非贪婪的数量词"ab*?",将找到"a"。


1.3. 反斜杠的问题

与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。

假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\":

第一个和第三个用于在编程语言里将第二个和第四个转义成反斜杠,

转换成两个反斜杠\\后再在正则表达式里转义成一个反斜杠用来匹配反斜杠\。

这样显然是非常麻烦的。

Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。

同样,匹配一个数字的"\\d"可以写成r"\d"。

有了原生字符串,妈妈再也不用担心我的反斜杠问题~



二、 介绍re模块

2.1.  Compile

Python通过re模块提供对正则表达式的支持。

使用re的一般步骤是:

Step1:先将正则表达式的字符串形式编译为Pattern实例。

Step2:然后使用Pattern实例处理文本并获得匹配结果(一个Match实例)。

Step3:最后使用Match实例获得信息,进行其他的操作。

我们新建一个re01.py来试验一下re的应用:

[python]  view plain copy
  1. # -*- coding: utf-8 -*-  
  2. #一个简单的re实例,匹配字符串中的hello字符串  
  3.   
  4. #导入re模块  
  5. import re  
  6.    
  7. # 将正则表达式编译成Pattern对象,注意hello前面的r的意思是“原生字符串”  
  8. pattern = re.compile(r'hello')  
  9.    
  10. # 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None  
  11. match1 = pattern.match('hello world!')  
  12. match2 = pattern.match('helloo world!')  
  13. match3 = pattern.match('helllo world!')  
  14.   
  15. #如果match1匹配成功  
  16. if match1:  
  17.     # 使用Match获得分组信息  
  18.     print match1.group()  
  19. else:  
  20.     print 'match1匹配失败!'  
  21.   
  22.   
  23. #如果match2匹配成功  
  24. if match2:  
  25.     # 使用Match获得分组信息  
  26.     print match2.group()  
  27. else:  
  28.     print 'match2匹配失败!'  
  29.   
  30.   
  31. #如果match3匹配成功  
  32. if match3:  
  33.     # 使用Match获得分组信息  
  34.     print match3.group()  
  35. else:  
  36.     print 'match3匹配失败!'  

可以看到控制台输出了匹配的三个结果:

Python之网络爬虫完全教程_第8张图片

下面来具体看看代码中的关键方法。

★ re.compile(strPattern[, flag]):

这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为Pattern对象。

第二个参数flag是匹配模式,取值可以使用按位或运算符'|'表示同时生效,比如re.I | re.M。

另外,你也可以在regex字符串中指定模式,

比如re.compile('pattern', re.I | re.M)与re.compile('(?im)pattern')是等价的。

可选值有:

  •     re.I(全拼:IGNORECASE): 忽略大小写(括号内是完整写法,下同)
  •    re.M(全拼:MULTILINE): 多行模式,改变'^'和'$'的行为(参见上图)
  •     re.S(全拼:DOTALL): 点任意匹配模式,改变'.'的行为
  •     re.L(全拼:LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
  •     re.U(全拼:UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
  •     re.X(全拼:VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。


以下两个正则表达式是等价的:

[python]  view plain copy
  1. # -*- coding: utf-8 -*-  
  2. #两个等价的re匹配,匹配一个小数  
  3. import re  
  4.   
  5. a = re.compile(r"""\d +  # the integral part 
  6.                    \.    # the decimal point 
  7.                    \d *  # some fractional digits""", re.X)  
  8.   
  9. b = re.compile(r"\d+\.\d*")  
  10.   
  11. match11 = a.match('3.1415')  
  12. match12 = a.match('33')  
  13. match21 = b.match('3.1415')  
  14. match22 = b.match('33')   
  15.   
  16. if match11:  
  17.     # 使用Match获得分组信息  
  18.     print match11.group()  
  19. else:  
  20.     print u'match11不是小数'  
  21.       
  22. if match12:  
  23.     # 使用Match获得分组信息  
  24.     print match12.group()  
  25. else:  
  26.     print u'match12不是小数'  
  27.       
  28. if match21:  
  29.     # 使用Match获得分组信息  
  30.     print match21.group()  
  31. else:  
  32.     print u'match21不是小数'  
  33.   
  34. if match22:  
  35.     # 使用Match获得分组信息  
  36.     print match22.group()  
  37. else:  
  38.     print u'match22不是小数'  

re提供了众多模块方法用于完成正则表达式的功能。

这些方法可以使用Pattern实例的相应方法替代,唯一的好处是少写一行re.compile()代码,

但同时也无法复用编译后的Pattern对象。

这些方法将在Pattern类的实例方法部分一起介绍。

如一开始的hello实例可以简写为:

[html]  view plain copy
  1. # -*- coding: utf-8 -*-  
  2. #一个简单的re实例,匹配字符串中的hello字符串  
  3. import re  
  4.   
  5. m = re.match(r'hello', 'hello world!')  
  6. print m.group()  

re模块还提供了一个方法escape(string),用于将string中的正则表达式元字符如*/+/?等之前加上转义符再返回


2.2. Match

Match对象是一次匹配的结果,包含了很多关于此次匹配的信息,可以使用Match提供的可读属性或方法来获取这些信息。

属性:

  1. string: 匹配时使用的文本。
  2. re: 匹配时使用的Pattern对象。
  3. pos: 文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
  4. endpos: 文本中正则表达式结束搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
  5. lastindex: 最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None。
  6. lastgroup: 最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将为None。

方法:

  1. group([group1, …]):
    获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名;编号0代表整个匹配的子串;不填写参数时,返回group(0);没有截获字符串的组返回None;截获了多次的组返回最后一次截获的子串。
  2. groups([default]): 
    以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。default表示没有截获字符串的组以这个值替代,默认为None。
  3. groupdict([default]):
    返回以有别名的组的别名为键、以该组截获的子串为值的字典,没有别名的组不包含在内。default含义同上。
  4. start([group]): 
    返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。group默认值为0。
  5. end([group]):
    返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1)。group默认值为0。
  6. span([group]):
    返回(start(group), end(group))。
  7. expand(template): 
    将匹配到的分组代入template中然后返回。template中可以使用\id或\g、\g引用分组,但不能使用编号0。\id与\g是等价的;但\10将被认为是第10个分组,如果你想表达\1之后是字符'0',只能使用\g<1>0。
下面来用一个py实例输出所有的内容加深理解:

[python]  view plain copy
  1. # -*- coding: utf-8 -*-  
  2. #一个简单的match实例  
  3.   
  4. import re  
  5. # 匹配如下内容:单词+空格+单词+任意字符  
  6. m = re.match(r'(\w+) (\w+)(?P.*)''hello world!')  
  7.   
  8. print "m.string:", m.string  
  9. print "m.re:", m.re  
  10. print "m.pos:", m.pos  
  11. print "m.endpos:", m.endpos  
  12. print "m.lastindex:", m.lastindex  
  13. print "m.lastgroup:", m.lastgroup  
  14.   
  15. print "m.group():", m.group()  
  16. print "m.group(1,2):", m.group(12)  
  17. print "m.groups():", m.groups()  
  18. print "m.groupdict():", m.groupdict()  
  19. print "m.start(2):", m.start(2)  
  20. print "m.end(2):", m.end(2)  
  21. print "m.span(2):", m.span(2)  
  22. print r"m.expand(r'\g<2> \g<1>\g<3>'):", m.expand(r'\2 \1\3')  
  23.    
  24. ### output ###  
  25. # m.string: hello world!  
  26. # m.re: <_sre.SRE_Pattern object at 0x016E1A38>  
  27. # m.pos: 0  
  28. # m.endpos: 12  
  29. # m.lastindex: 3  
  30. # m.lastgroup: sign  
  31. # m.group(1,2): ('hello', 'world')  
  32. # m.groups(): ('hello', 'world', '!')  
  33. # m.groupdict(): {'sign': '!'}  
  34. # m.start(2): 6  
  35. # m.end(2): 11  
  36. # m.span(2): (6, 11)  
  37. # m.expand(r'\2 \1\3'): world hello!  


2.3. Pattern

Pattern对象是一个编译好的正则表达式,通过Pattern提供的一系列方法可以对文本进行匹配查找。

Pattern不能直接实例化,必须使用re.compile()进行构造,也就是re.compile()返回的对象。

Pattern提供了几个可读属性用于获取表达式的相关信息:

  1. pattern: 编译时用的表达式字符串。
  2. flags: 编译时用的匹配模式。数字形式。
  3. groups: 表达式中分组的数量。
  4. groupindex: 以表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。
可以用下面这个例子查看pattern的属性:

[python]  view plain copy
  1. # -*- coding: utf-8 -*-  
  2. #一个简单的pattern实例  
  3.   
  4. import re  
  5. p = re.compile(r'(\w+) (\w+)(?P.*)', re.DOTALL)  
  6.    
  7. print "p.pattern:", p.pattern  
  8. print "p.flags:", p.flags  
  9. print "p.groups:", p.groups  
  10. print "p.groupindex:", p.groupindex  
  11.    
  12. ### output ###  
  13. # p.pattern: (\w+) (\w+)(?P.*)  
  14. # p.flags: 16  
  15. # p.groups: 3  
  16. # p.groupindex: {'sign': 3}  

下面重点介绍一下pattern的实例方法及其使用。

1.match

match(string[, pos[, endpos]]) | re.match(pattern, string[, flags]):

这个方法将从string的pos下标处起尝试匹配pattern;

如果pattern结束时仍可匹配,则返回一个Match对象;

如果匹配过程中pattern无法匹配,或者匹配未结束就已到达endpos,则返回None。

pos和endpos的默认值分别为0和len(string);

re.match()无法指定这两个参数,参数flags用于编译pattern时指定匹配模式。

注意:这个方法并不是完全匹配。

当pattern结束时若string还有剩余字符,仍然视为成功。

想要完全匹配,可以在表达式末尾加上边界匹配符'$'。

下面来看一个Match的简单案例:

[python]  view plain copy
  1. # encoding: UTF-8  
  2. import re  
  3.    
  4. # 将正则表达式编译成Pattern对象  
  5. pattern = re.compile(r'hello')  
  6.    
  7. # 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None  
  8. match = pattern.match('hello world!')  
  9.    
  10. if match:  
  11.     # 使用Match获得分组信息  
  12.     print match.group()  
  13.    
  14. ### 输出 ###  
  15. # hello  



2.search
search(string[, pos[, endpos]]) | re.search(pattern, string[, flags]): 
这个方法用于查找字符串中可以匹配成功的子串。

从string的pos下标处起尝试匹配pattern,

如果pattern结束时仍可匹配,则返回一个Match对象;

若无法匹配,则将pos加1后重新尝试匹配;

直到pos=endpos时仍无法匹配则返回None。

pos和endpos的默认值分别为0和len(string));

re.search()无法指定这两个参数,参数flags用于编译pattern时指定匹配模式。

那么它和match有什么区别呢?

match()函数只检测re是不是在string的开始位置匹配,

search()会扫描整个string查找匹配,


match()只有在0位置匹配成功的话才有返回,如果不是开始位置匹配成功的话,match()就返回none
例如:
print(re.match(‘super’, ‘superstition’).span())

会返回(0, 5)

print(re.match(‘super’, ‘insuperable’))

则返回None

search()会扫描整个字符串并返回第一个成功的匹配
例如:

print(re.search(‘super’, ‘superstition’).span())

返回(0, 5)
print(re.search(‘super’, ‘insuperable’).span())

返回(2, 7)

看一个search的实例:

[python]  view plain copy
  1. # -*- coding: utf-8 -*-  
  2. #一个简单的search实例  
  3.   
  4. import re  
  5.    
  6. # 将正则表达式编译成Pattern对象  
  7. pattern = re.compile(r'world')  
  8.    
  9. # 使用search()查找匹配的子串,不存在能匹配的子串时将返回None  
  10. # 这个例子中使用match()无法成功匹配  
  11. match = pattern.search('hello world!')  
  12.    
  13. if match:  
  14.     # 使用Match获得分组信息  
  15.     print match.group()  
  16.    
  17. ### 输出 ###  
  18. # world  



3.split

split(string[, maxsplit]) | re.split(pattern, string[, maxsplit]):
按照能够匹配的子串将string分割后返回列表。

maxsplit用于指定最大分割次数,不指定将全部分割。

[python]  view plain copy
  1. import re  
  2.    
  3. p = re.compile(r'\d+')  
  4. print p.split('one1two2three3four4')  
  5.    
  6. ### output ###  
  7. # ['one', 'two', 'three', 'four', '']  


4.findall

findall(string[, pos[, endpos]]) | re.findall(pattern, string[, flags]):
搜索string,以列表形式返回全部能匹配的子串。

[python]  view plain copy
  1. import re  
  2.    
  3. p = re.compile(r'\d+')  
  4. print p.findall('one1two2three3four4')  
  5.    
  6. ### output ###  
  7. # ['1', '2', '3', '4']  


5.finditer

finditer(string[, pos[, endpos]]) | re.finditer(pattern, string[, flags]):
搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。

[html]  view plain copy
  1. import re  
  2.    
  3. p = re.compile(r'\d+')  
  4. for m in p.finditer('one1two2three3four4'):  
  5.     print m.group(),  
  6.    
  7. ### output ###  
  8. # 1 2 3 4  

6.sub

sub(repl, string[, count]) | re.sub(pattern, repl, string[, count]):
使用repl替换string中每一个匹配的子串后返回替换后的字符串。 
当repl是一个字符串时,可以使用\id或\g、\g引用分组,但不能使用编号0。 
当repl是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。 
count用于指定最多替换次数,不指定时全部替换。

[python]  view plain copy
  1. import re  
  2.    
  3. p = re.compile(r'(\w+) (\w+)')  
  4. s = 'i say, hello world!'  
  5.    
  6. print p.sub(r'\2 \1', s)  
  7.    
  8. def func(m):  
  9.     return m.group(1).title() + ' ' + m.group(2).title()  
  10.    
  11. print p.sub(func, s)  
  12.    
  13. ### output ###  
  14. # say i, world hello!  
  15. # I Say, Hello World!  

7.subn

subn(repl, string[, count]) |re.sub(pattern, repl, string[, count]):
返回 (sub(repl, string[, count]), 替换次数)。

[python]  view plain copy
  1. import re  
  2.    
  3. p = re.compile(r'(\w+) (\w+)')  
  4. s = 'i say, hello world!'  
  5.    
  6. print p.subn(r'\2 \1', s)  
  7.    
  8. def func(m):  
  9.     return m.group(1).title() + ' ' + m.group(2).title()  
  10.    
  11. print p.subn(func, s)  
  12.    
  13. ### output ###  
  14. # ('say i, world hello!', 2)  
  15. # ('I Say, Hello World!', 2)  

至此,Python的正则表达式基本介绍就算是完成了^_^


[Python]网络爬虫(八):糗事百科的网络爬虫(v0.3)源码及解析(简化更新)


Q&A:

1.为什么有段时间显示糗事百科不可用?

答:前段时间因为糗事百科添加了Header的检验,导致无法爬取,需要在代码中模拟Header。现在代码已经作了修改,可以正常使用。


2.为什么需要单独新建个线程?

答:基本流程是这样的:爬虫在后台新起一个线程,一直爬取两页的糗事百科,如果剩余不足两页,则再爬一页。用户按下回车只是从库存中获取最新的内容,而不是上网获取,所以浏览更顺畅。也可以把加载放在主线程,不过这样会导致爬取过程中等待时间过长的问题。





项目内容:

用Python写的糗事百科的网络爬虫。

使用方法:

新建一个Bug.py文件,然后将代码复制到里面后,双击运行。

程序功能:

在命令提示行中浏览糗事百科。

原理解释:

首先,先浏览一下糗事百科的主页:http://www.qiushibaike.com/hot/page/1

可以看出来,链接中page/后面的数字就是对应的页码,记住这一点为以后的编写做准备。

然后,右击查看页面源码:

Python之网络爬虫完全教程_第9张图片

观察发现,每一个段子都用div标记,其中class必为content,title是发帖时间,我们只需要用正则表达式将其“扣”出来就可以了。

明白了原理之后,剩下的就是正则表达式的内容了,可以参照这篇博文:

http://blog.csdn.net/wxg694175346/article/details/8929576


运行效果:

Python之网络爬虫完全教程_第10张图片



[python]  view plain copy
  1. "189704" snippet_file_name="blog_20140215_1_8153875" name="code" class="python"># -*- coding: utf-8 -*-    
  2.      
  3. import urllib2    
  4. import urllib    
  5. import re    
  6. import thread    
  7. import time    
  8.   
  9.     
  10. #----------- 加载处理糗事百科 -----------    
  11. class Spider_Model:    
  12.         
  13.     def __init__(self):    
  14.         self.page = 1    
  15.         self.pages = []    
  16.         self.enable = False    
  17.     
  18.     # 将所有的段子都扣出来,添加到列表中并且返回列表    
  19.     def GetPage(self,page):    
  20.         myUrl = "http://m.qiushibaike.com/hot/page/" + page    
  21.         user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'   
  22.         headers = { 'User-Agent' : user_agent }   
  23.         req = urllib2.Request(myUrl, headers = headers)   
  24.         myResponse = urllib2.urlopen(req)  
  25.         myPage = myResponse.read()    
  26.         #encode的作用是将unicode编码转换成其他编码的字符串    
  27.         #decode的作用是将其他编码的字符串转换成unicode编码    
  28.         unicodePage = myPage.decode("utf-8")    
  29.     
  30.         # 找出所有class="content"的div标记    
  31.         #re.S是任意匹配模式,也就是.可以匹配换行符    
  32.         myItems = re.findall('(.*?)
',unicodePage,re.S)    
  •         items = []    
  •         for item in myItems:    
  •             # item 中第一个是div的标题,也就是时间    
  •             # item 中第二个是div的内容,也就是内容    
  •             items.append([item[0].replace("\n",""),item[1].replace("\n","")])    
  •         return items    
  •     
  •     # 用于加载新的段子    
  •     def LoadPage(self):    
  •         # 如果用户未输入quit则一直运行    
  •         while self.enable:    
  •             # 如果pages数组中的内容小于2个    
  •             if len(self.pages) < 2:    
  •                 try:    
  •                     # 获取新的页面中的段子们    
  •                     myPage = self.GetPage(str(self.page))    
  •                     self.page += 1    
  •                     self.pages.append(myPage)    
  •                 except:    
  •                     print '无法链接糗事百科!'    
  •             else:    
  •                 time.sleep(1)    
  •             
  •     def ShowPage(self,nowPage,page):    
  •         for items in nowPage:    
  •             print u'第%d页' % page , items[0]  , items[1]    
  •             myInput = raw_input()    
  •             if myInput == "quit":    
  •                 self.enable = False    
  •                 break    
  •             
  •     def Start(self):    
  •         self.enable = True    
  •         page = self.page    
  •     
  •         print u'正在加载中请稍候......'    
  •             
  •         # 新建一个线程在后台加载段子并存储    
  •         thread.start_new_thread(self.LoadPage,())    
  •             
  •         #----------- 加载处理糗事百科 -----------    
  •         while self.enable:    
  •             # 如果self的page数组中存有元素    
  •             if self.pages:    
  •                 nowPage = self.pages[0]    
  •                 del self.pages[0]    
  •                 self.ShowPage(nowPage,page)    
  •                 page += 1    
  •     
  •     
  • #----------- 程序的入口处 -----------    
  • print u"""  
  • ---------------------------------------  
  •    程序:糗百爬虫  
  •    版本:0.3  
  •    作者:why  
  •    日期:2014-06-03  
  •    语言:Python 2.7  
  •    操作:输入quit退出阅读糗事百科  
  •    功能:按下回车依次浏览今日的糗百热点  
  • ---------------------------------------  
  • """  
  •     
  •     
  • print u'请按下回车浏览今日的糗百内容:'    
  • raw_input(' ')    
  • myModel = Spider_Model()    
  • myModel.Start()    


  •  


  •  

    [Python]网络爬虫(九):百度贴吧的网络爬虫(v0.4)源码及解析


    百度贴吧的爬虫制作和糗百的爬虫制作原理基本相同,都是通过查看源码扣出关键数据,然后将其存储到本地txt文件。

    源码下载:

    http://download.csdn.net/detail/wxg694175346/6925583

    项目内容:

    用Python写的百度贴吧的网络爬虫。

    使用方法:

    新建一个BugBaidu.py文件,然后将代码复制到里面后,双击运行。

    程序功能:

    将贴吧中楼主发布的内容打包txt存储到本地。

    原理解释:

    首先,先浏览一下某一条贴吧,点击只看楼主并点击第二页之后url发生了一点变化,变成了:

    http://tieba.baidu.com/p/2296712428?see_lz=1&pn=1

    可以看出来,see_lz=1是只看楼主,pn=1是对应的页码,记住这一点为以后的编写做准备。

    这就是我们需要利用的url。

    接下来就是查看页面源码。

    首先把题目抠出来存储文件的时候会用到。

    可以看到百度使用gbk编码,标题使用h1标记:

    [html]  view plain copy
    1. <h1 class="core_title_txt" title="【原创】时尚首席(关于时尚,名利,事业,爱情,励志)">【原创】时尚首席(关于时尚,名利,事业,爱情,励志)h1>  

    同样,正文部分用div和class综合标记,接下来要做的只是用正则表达式来匹配即可。

    运行截图:

    Python之网络爬虫完全教程_第11张图片

    生成的txt文件:

    Python之网络爬虫完全教程_第12张图片


    [python]  view plain copy
    1. # -*- coding: utf-8 -*-  
    2. #---------------------------------------  
    3. #   程序:百度贴吧爬虫  
    4. #   版本:0.5  
    5. #   作者:why  
    6. #   日期:2013-05-16  
    7. #   语言:Python 2.7  
    8. #   操作:输入网址后自动只看楼主并保存到本地文件  
    9. #   功能:将楼主发布的内容打包txt存储到本地。  
    10. #---------------------------------------  
    11.    
    12. import string  
    13. import urllib2  
    14. import re  
    15.   
    16. #----------- 处理页面上的各种标签 -----------  
    17. class HTML_Tool:  
    18.     # 用非 贪婪模式 匹配 \t 或者 \n 或者 空格 或者 超链接 或者 图片  
    19.     BgnCharToNoneRex = re.compile("(\t|\n| ||)")  
    20.       
    21.     # 用非 贪婪模式 匹配 任意<>标签  
    22.     EndCharToNoneRex = re.compile("<.*?>")  
    23.   
    24.     # 用非 贪婪模式 匹配 任意

      标签  

    25.     BgnPartRex = re.compile("")  
    26.     CharToNewLineRex = re.compile("(
      |

      ||
      |
      )"
      )  
    27.     CharToNextTabRex = re.compile("")  
    28.   
    29.     # 将一些html的符号实体转变为原始符号  
    30.     replaceTab = [("<","<"),(">",">"),("&","&"),("&","\""),(" "," ")]  
    31.       
    32.     def Replace_Char(self,x):  
    33.         x = self.BgnCharToNoneRex.sub("",x)  
    34.         x = self.BgnPartRex.sub("\n    ",x)  
    35.         x = self.CharToNewLineRex.sub("\n",x)  
    36.         x = self.CharToNextTabRex.sub("\t",x)  
    37.         x = self.EndCharToNoneRex.sub("",x)  
    38.   
    39.         for t in self.replaceTab:    
    40.             x = x.replace(t[0],t[1])    
    41.         return x    
    42.       
    43. class Baidu_Spider:  
    44.     # 申明相关的属性  
    45.     def __init__(self,url):    
    46.         self.myUrl = url + '?see_lz=1'  
    47.         self.datas = []  
    48.         self.myTool = HTML_Tool()  
    49.         print u'已经启动百度贴吧爬虫,咔嚓咔嚓'  
    50.     
    51.     # 初始化加载页面并将其转码储存  
    52.     def baidu_tieba(self):  
    53.         # 读取页面的原始信息并将其从gbk转码  
    54.         myPage = urllib2.urlopen(self.myUrl).read().decode("gbk")  
    55.         # 计算楼主发布内容一共有多少页  
    56.         endPage = self.page_counter(myPage)  
    57.         # 获取该帖的标题  
    58.         title = self.find_title(myPage)  
    59.         print u'文章名称:' + title  
    60.         # 获取最终的数据  
    61.         self.save_data(self.myUrl,title,endPage)  
    62.   
    63.     #用来计算一共有多少页  
    64.     def page_counter(self,myPage):  
    65.         # 匹配 "共有12页" 来获取一共有多少页  
    66.         myMatch = re.search(r'class="red">(\d+?)', myPage, re.S)  
    67.         if myMatch:    
    68.             endPage = int(myMatch.group(1))  
    69.             print u'爬虫报告:发现楼主共有%d页的原创内容' % endPage  
    70.         else:  
    71.             endPage = 0  
    72.             print u'爬虫报告:无法计算楼主发布内容有多少页!'  
    73.         return endPage  
    74.   
    75.     # 用来寻找该帖的标题  
    76.     def find_title(self,myPage):  
    77.         # 匹配 xxxxxxxxxx

     找出标题  
  •         myMatch = re.search(r'(.*?)', myPage, re.S)  
  •         title = u'暂无标题'  
  •         if myMatch:  
  •             title  = myMatch.group(1)  
  •         else:  
  •             print u'爬虫报告:无法加载文章标题!'  
  •         # 文件名不能包含以下字符: \ / : * ? " < > |  
  •         title = title.replace('\\','').replace('/','').replace(':','').replace('*','').replace('?','').replace('"','').replace('>','').replace('<','').replace('|','')  
  •         return title  
  •   
  •   
  •     # 用来存储楼主发布的内容  
  •     def save_data(self,url,title,endPage):  
  •         # 加载页面数据到数组中  
  •         self.get_data(url,endPage)  
  •         # 打开本地文件  
  •         f = open(title+'.txt','w+')  
  •         f.writelines(self.datas)  
  •         f.close()  
  •         print u'爬虫报告:文件已下载到本地并打包成txt文件'  
  •         print u'请按任意键退出...'  
  •         raw_input();  
  •   
  •     # 获取页面源码并将其存储到数组中  
  •     def get_data(self,url,endPage):  
  •         url = url + '&pn='  
  •         for i in range(1,endPage+1):  
  •             print u'爬虫报告:爬虫%d号正在加载中...' % i  
  •             myPage = urllib2.urlopen(url + str(i)).read()  
  •             # 将myPage中的html代码处理并存储到datas里面  
  •             self.deal_data(myPage.decode('gbk'))  
  •               
  •   
  •     # 将内容从页面代码中抠出来  
  •     def deal_data(self,myPage):  
  •         myItems = re.findall('id="post_content.*?>(.*?)
  • ',myPage,re.S)  
  •         for item in myItems:  
  •             data = self.myTool.Replace_Char(item.replace("\n","").encode('gbk'))  
  •             self.datas.append(data+'\n')  
  •   
  •   
  •   
  • #-------- 程序入口处 ------------------  
  • print u"""#--------------------------------------- 
  • #   程序:百度贴吧爬虫 
  • #   版本:0.5 
  • #   作者:why 
  • #   日期:2013-05-16 
  • #   语言:Python 2.7 
  • #   操作:输入网址后自动只看楼主并保存到本地文件 
  • #   功能:将楼主发布的内容打包txt存储到本地。 
  • #--------------------------------------- 
  • """  
  •   
  • # 以某小说贴吧为例子  
  • # bdurl = 'http://tieba.baidu.com/p/2296712428?see_lz=1&pn=1'  
  •   
  • print u'请输入贴吧的地址最后的数字串:'  
  • bdurl = 'http://tieba.baidu.com/p/' + str(raw_input(u'http://tieba.baidu.com/p/'))   
  •   
  • #调用  
  • mySpider = Baidu_Spider(bdurl)  
  • mySpider.baidu_tieba()  

  • [Python]网络爬虫(十):一个爬虫的诞生全过程(以山东大学绩点运算为例)


    先来说一下我们学校的网站:

    http://jwxt.sdu.edu.cn:7777/zhxt_bks/zhxt_bks.html

    查询成绩需要登录,然后显示各学科成绩,但是只显示成绩而没有绩点,也就是加权平均分。

    Python之网络爬虫完全教程_第13张图片

    显然这样手动计算绩点是一件非常麻烦的事情。所以我们可以用python做一个爬虫来解决这个问题。



    1.决战前夜

    先来准备一下工具:HttpFox插件。

    这是一款http协议分析插件,分析页面请求和响应的时间、内容、以及浏览器用到的COOKIE等。

    以我为例,安装在火狐上即可,效果如图:Python之网络爬虫完全教程_第14张图片

    可以非常直观的查看相应的信息。

    点击start是开始检测,点击stop暂停检测,点击clear清除内容。

    一般在使用之前,点击stop暂停,然后点击clear清屏,确保看到的是访问当前页面获得的数据。



    2.深入敌后

    下面就去山东大学的成绩查询网站,看一看在登录的时候,到底发送了那些信息。

    先来到登录页面,把httpfox打开,clear之后,点击start开启检测:

    Python之网络爬虫完全教程_第15张图片


    输入完了个人信息,确保httpfox处于开启状态,然后点击确定提交信息,实现登录。

    这个时候可以看到,httpfox检测到了三条信息:

    Python之网络爬虫完全教程_第16张图片

    这时点击stop键,确保捕获到的是访问该页面之后反馈的数据,以便我们做爬虫的时候模拟登陆使用。



    3.庖丁解牛

    乍一看我们拿到了三个数据,两个是GET的一个是POST的,但是它们到底是什么,应该怎么用,我们还一无所知。

    所以,我们需要挨个查看一下捕获到的内容。

    先看POST的信息:

    Python之网络爬虫完全教程_第17张图片

    既然是POST的信息,我们就直接看PostData即可。

    可以看到一共POST两个数据,stuid和pwd。

    并且从Type的Redirect to可以看出,POST完毕之后跳转到了bks_login2.loginmessage页面。

    由此看出,这个数据是点击确定之后提交的表单数据。

    点击cookie标签,看看cookie信息:

    Python之网络爬虫完全教程_第18张图片

    没错,收到了一个ACCOUNT的cookie,并且在session结束之后自动销毁。

    那么提交之后收到了哪些信息呢?

    我们来看看后面的两个GET数据。

    先看第一个,我们点击content标签可以查看收到的内容,是不是有一种生吞活剥的快感-。-HTML源码暴露无疑了:

    Python之网络爬虫完全教程_第19张图片

    看来这个只是显示页面的html源码而已,点击cookie,查看cookie的相关信息:

    Python之网络爬虫完全教程_第20张图片


    啊哈,原来html页面的内容是发送了cookie信息之后才接受到的。

    再来看看最后一个接收到的信息:

    Python之网络爬虫完全教程_第21张图片

    大致看了一下应该只是一个叫做style.css的css文件,对我们没有太大的作用。




    4.冷静应战

    既然已经知道了我们向服务器发送了什么数据,也知道了我们接收到了什么数据,基本的流程如下:

    • 首先,我们POST学号和密码--->然后返回cookie的值
    • 然后发送cookie给服务器--->返回页面信息。
    • 获取到成绩页面的数据,用正则表达式将成绩和学分单独取出并计算加权平均数。

    OK,看上去好像很简单的样纸。那下面我们就来试试看吧。

    但是在实验之前,还有一个问题没有解决,就是POST的数据到底发送到了哪里?

    再来看一下当初的页面:

    Python之网络爬虫完全教程_第22张图片

    很明显是用一个html框架来实现的,也就是说,我们在地址栏看到的地址并不是右边提交表单的地址。

    那么怎样才能获得真正的地址-。-右击查看页面源代码:

    嗯没错,那个name="w_right"的就是我们要的登录页面。

    网站的原来的地址是:

    http://jwxt.sdu.edu.cn:7777/zhxt_bks/zhxt_bks.html

    所以,真正的表单提交的地址应该是:

    http://jwxt.sdu.edu.cn:7777/zhxt_bks/xk_login.html

    输入一看,果不其然:

    Python之网络爬虫完全教程_第23张图片

    靠居然是清华大学的选课系统。。。目测是我校懒得做页面了就直接借了。。结果连标题都不改一下。。。

    但是这个页面依旧不是我们需要的页面,因为我们的POST数据提交到的页面,应该是表单form的ACTION中提交到的页面。

    也就是说,我们需要查看源码,来知道POST数据到底发送到了哪里:

    Python之网络爬虫完全教程_第24张图片


    嗯,目测这个才是提交POST数据的地址。

    整理到地址栏中,完整的地址应该如下:

    http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login

    (获取的方式很简单,在火狐浏览器中直接点击那个链接就能看到这个链接的地址了)


    5.小试牛刀

    接下来的任务就是:用python模拟发送一个POST的数据并取到返回的cookie值。

    关于cookie的操作可以看看这篇博文:

    http://blog.csdn.net/wxg694175346/article/details/8925978

    我们先准备一个POST的数据,再准备一个cookie的接收,然后写出源码如下:

    [python]  view plain copy
    1. # -*- coding: utf-8 -*-  
    2. #---------------------------------------  
    3. #   程序:山东大学爬虫  
    4. #   版本:0.1  
    5. #   作者:why  
    6. #   日期:2013-07-12  
    7. #   语言:Python 2.7  
    8. #   操作:输入学号和密码  
    9. #   功能:输出成绩的加权平均值也就是绩点  
    10. #---------------------------------------  
    11.   
    12. import urllib    
    13. import urllib2  
    14. import cookielib  
    15.   
    16. cookie = cookielib.CookieJar()    
    17. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))  
    18.   
    19. #需要POST的数据#  
    20. postdata=urllib.urlencode({    
    21.     'stuid':'201100300428',    
    22.     'pwd':'921030'    
    23. })  
    24.   
    25. #自定义一个请求#  
    26. req = urllib2.Request(    
    27.     url = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login',    
    28.     data = postdata  
    29. )  
    30.   
    31. #访问该链接#  
    32. result = opener.open(req)  
    33.   
    34. #打印返回的内容#  
    35. print result.read()     

    如此这般之后,再看看运行的效果:

    Python之网络爬虫完全教程_第25张图片

    ok,如此这般,我们就算模拟登陆成功了。


    6.偷天换日

    接下来的任务就是用爬虫获取到学生的成绩。

    再来看看源网站。

    开启HTTPFOX之后,点击查看成绩,发现捕获到了如下的数据:

    Python之网络爬虫完全教程_第26张图片

    点击第一个GET的数据,查看内容可以发现Content就是获取到的成绩的内容。


    而获取到的页面链接,从页面源代码中右击查看元素,可以看到点击链接之后跳转的页面(火狐浏览器只需要右击,“查看此框架”,即可):

    Python之网络爬虫完全教程_第27张图片

    从而可以得到查看成绩的链接如下:

    http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bkscjcx.curscopre


    7.万事俱备

    现在万事俱备啦,所以只需要把链接应用到爬虫里面,看看能否查看到成绩的页面。

    从httpfox可以看到,我们发送了一个cookie才能返回成绩的信息,所以我们就用python模拟一个cookie的发送,以此来请求成绩的信息:

    [python]  view plain copy
    1. # -*- coding: utf-8 -*-  
    2. #---------------------------------------  
    3. #   程序:山东大学爬虫  
    4. #   版本:0.1  
    5. #   作者:why  
    6. #   日期:2013-07-12  
    7. #   语言:Python 2.7  
    8. #   操作:输入学号和密码  
    9. #   功能:输出成绩的加权平均值也就是绩点  
    10. #---------------------------------------  
    11.   
    12. import urllib    
    13. import urllib2  
    14. import cookielib  
    15.   
    16. #初始化一个CookieJar来处理Cookie的信息#  
    17. cookie = cookielib.CookieJar()  
    18.   
    19. #创建一个新的opener来使用我们的CookieJar#  
    20. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))  
    21.   
    22. #需要POST的数据#  
    23. postdata=urllib.urlencode({    
    24.     'stuid':'201100300428',    
    25.     'pwd':'921030'    
    26. })  
    27.   
    28. #自定义一个请求#  
    29. req = urllib2.Request(    
    30.     url = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login',    
    31.     data = postdata  
    32. )  
    33.   
    34. #访问该链接#  
    35. result = opener.open(req)  
    36.   
    37. #打印返回的内容#  
    38. print result.read()  
    39.   
    40. #打印cookie的值  
    41. for item in cookie:    
    42.     print 'Cookie:Name = '+item.name    
    43.     print 'Cookie:Value = '+item.value  
    44.   
    45.       
    46. #访问该链接#  
    47. result = opener.open('http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bkscjcx.curscopre')  
    48.   
    49. #打印返回的内容#  
    50. print result.read()  

    按下F5运行即可,看看捕获到的数据吧:

    Python之网络爬虫完全教程_第28张图片

    既然这样就没有什么问题了吧,用正则表达式将数据稍稍处理一下,取出学分和相应的分数就可以了。



    8.手到擒来

    这么一大堆html源码显然是不利于我们处理的,下面要用正则表达式来抠出必须的数据。

    关于正则表达式的教程可以看看这个博文:

    http://blog.csdn.net/wxg694175346/article/details/8929576

    我们来看看成绩的源码:

    Python之网络爬虫完全教程_第29张图片


    既然如此,用正则表达式就易如反掌了。


    我们将代码稍稍整理一下,然后用正则来取出数据:

    [python]  view plain copy
    1. # -*- coding: utf-8 -*-  
    2. #---------------------------------------  
    3. #   程序:山东大学爬虫  
    4. #   版本:0.1  
    5. #   作者:why  
    6. #   日期:2013-07-12  
    7. #   语言:Python 2.7  
    8. #   操作:输入学号和密码  
    9. #   功能:输出成绩的加权平均值也就是绩点  
    10. #---------------------------------------  
    11.   
    12. import urllib    
    13. import urllib2  
    14. import cookielib  
    15. import re  
    16.   
    17. class SDU_Spider:    
    18.     # 申明相关的属性    
    19.     def __init__(self):      
    20.         self.loginUrl = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login'   # 登录的url  
    21.         self.resultUrl = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bkscjcx.curscopre' # 显示成绩的url  
    22.         self.cookieJar = cookielib.CookieJar()                                      # 初始化一个CookieJar来处理Cookie的信息  
    23.         self.postdata=urllib.urlencode({'stuid':'201100300428','pwd':'921030'})     # POST的数据  
    24.         self.weights = []   #存储权重,也就是学分  
    25.         self.points = []    #存储分数,也就是成绩  
    26.         self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))  
    27.   
    28.     def sdu_init(self):  
    29.         # 初始化链接并且获取cookie  
    30.         myRequest = urllib2.Request(url = self.loginUrl,data = self.postdata)   # 自定义一个请求  
    31.         result = self.opener.open(myRequest)            # 访问登录页面,获取到必须的cookie的值  
    32.         result = self.opener.open(self.resultUrl)       # 访问成绩页面,获得成绩的数据  
    33.         # 打印返回的内容  
    34.         # print result.read()  
    35.         self.deal_data(result.read().decode('gbk'))  
    36.         self.print_data(self.weights);  
    37.         self.print_data(self.points);  
    38.   
    39.     # 将内容从页面代码中抠出来    
    40.     def deal_data(self,myPage):    
    41.         myItems = re.findall('.*?(.*?)

      .*?(.*?)

      .*?'
      ,myPage,re.S)     #获取到学分  
    42.         for item in myItems:  
    43.             self.weights.append(item[0].encode('gbk'))  
    44.             self.points.append(item[1].encode('gbk'))  
    45.   
    46.               
    47.     # 将内容从页面代码中抠出来  
    48.     def print_data(self,items):    
    49.         for item in items:    
    50.             print item  
    51.               
    52. #调用    
    53. mySpider = SDU_Spider()    
    54. mySpider.sdu_init()    

    水平有限,,正则是有点丑,。运行的效果如图:

    Python之网络爬虫完全教程_第30张图片

    ok,接下来的只是数据的处理问题了。。




    9.凯旋而归

    完整的代码如下,至此一个完整的爬虫项目便完工了。

    [python]  view plain copy
    1. # -*- coding: utf-8 -*-  
    2. #---------------------------------------  
    3. #   程序:山东大学爬虫  
    4. #   版本:0.1  
    5. #   作者:why  
    6. #   日期:2013-07-12  
    7. #   语言:Python 2.7  
    8. #   操作:输入学号和密码  
    9. #   功能:输出成绩的加权平均值也就是绩点  
    10. #---------------------------------------  
    11.   
    12. import urllib    
    13. import urllib2  
    14. import cookielib  
    15. import re  
    16. import string  
    17.   
    18.   
    19. class SDU_Spider:    
    20.     # 申明相关的属性    
    21.     def __init__(self):      
    22.         self.loginUrl = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bks_login2.login'   # 登录的url  
    23.         self.resultUrl = 'http://jwxt.sdu.edu.cn:7777/pls/wwwbks/bkscjcx.curscopre' # 显示成绩的url  
    24.         self.cookieJar = cookielib.CookieJar()                                      # 初始化一个CookieJar来处理Cookie的信息  
    25.         self.postdata=urllib.urlencode({'stuid':'201100300428','pwd':'921030'})     # POST的数据  
    26.         self.weights = []   #存储权重,也就是学分  
    27.         self.points = []    #存储分数,也就是成绩  
    28.         self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))  
    29.   
    30.     def sdu_init(self):  
    31.         # 初始化链接并且获取cookie  
    32.         myRequest = urllib2.Request(url = self.loginUrl,data = self.postdata)   # 自定义一个请求  
    33.         result = self.opener.open(myRequest)            # 访问登录页面,获取到必须的cookie的值  
    34.         result = self.opener.open(self.resultUrl)       # 访问成绩页面,获得成绩的数据  
    35.         # 打印返回的内容  
    36.         # print result.read()  
    37.         self.deal_data(result.read().decode('gbk'))  
    38.         self.calculate_date();  
    39.   
    40.     # 将内容从页面代码中抠出来    
    41.     def deal_data(self,myPage):    
    42.         myItems = re.findall('.*?(.*?)

      .*?(.*?)

      .*?'
      ,myPage,re.S)     #获取到学分  
    43.         for item in myItems:  
    44.             self.weights.append(item[0].encode('gbk'))  
    45.             self.points.append(item[1].encode('gbk'))  
    46.   
    47.     #计算绩点,如果成绩还没出来,或者成绩是优秀良好,就不运算该成绩  
    48.     def calculate_date(self):  
    49.         point = 0.0  
    50.         weight = 0.0  
    51.         for i in range(len(self.points)):  
    52.             if(self.points[i].isdigit()):  
    53.                 point += string.atof(self.points[i])*string.atof(self.weights[i])  
    54.                 weight += string.atof(self.weights[i])  
    55.         print point/weight  
    56.   
    57.               
    58. #调用    
    59. mySpider = SDU_Spider()    
    60. mySpider.sdu_init()    

    [Python]网络爬虫(11):亮剑!爬虫框架小抓抓Scrapy闪亮登场!


    前面十章爬虫笔记陆陆续续记录了一些简单的Python爬虫知识,

    用来解决简单的贴吧下载,绩点运算自然不在话下。

    不过要想批量下载大量的内容,比如知乎的所有的问答,那便显得游刃不有余了点。

    于是乎,爬虫框架Scrapy就这样出场了!

    Scrapy = Scrach+Python,Scrach这个单词是抓取的意思,

    暂且可以叫它:小抓抓吧。


    小抓抓的官网地址:点我点我。


    那么下面来简单的演示一下小抓抓Scrapy的安装流程。

    具体流程参照:官网教程

    友情提醒:一定要按照Python的版本下载,要不然安装的时候会提醒找不到Python。建议大家安装32位是因为有些版本的必备软件64位不好找。


    1.安装Python(建议32位)

    建议安装Python2.7.x,3.x貌似还不支持。

    安装完了记得配置环境,将python目录和python目录下的Scripts目录添加到系统环境变量的Path里。

    在cmd中输入python如果出现版本信息说明配置完毕。


    2.安装lxml

    lxml是一种使用 Python 编写的库,可以迅速、灵活地处理 XML。点击这里选择对应的Python版本安装。


    3.安装setuptools

    用来安装egg文件,点击这里下载python2.7的对应版本的setuptools。


    4.安装zope.interface

    可以使用第三步下载的setuptools来安装egg文件,现在也有exe版本,点击这里下载。


    5.安装Twisted

    Twisted是用Python实现的基于事件驱动的网络引擎框架,点击这里下载。


    6.安装pyOpenSSL

    pyOpenSSL是Python的OpenSSL接口,点击这里下载。


    7.安装win32py

    提供win32api,点击这里下载


    8.安装Scrapy

    终于到了激动人心的时候了!安装了那么多小部件之后终于轮到主角登场。

    直接在cmd中输入easy_install scrapy回车即可。


    9.检查安装

    打开一个cmd窗口,在任意位置执行scrapy命令,得到下列页面,表示环境配置成功。

    Python之网络爬虫完全教程_第31张图片


    [Python]网络爬虫(12):爬虫框架Scrapy的第一个爬虫示例入门教程


    (建议大家多看看官网教程:教程地址)


    我们使用dmoz.org这个网站来作为小抓抓一展身手的对象。


    首先先要回答一个问题。

    问:把网站装进爬虫里,总共分几步?

    答案很简单,四步:

    • 新建项目 (Project):新建一个新的爬虫项目
    • 明确目标(Items):明确你想要抓取的目标
    • 制作爬虫(Spider):制作爬虫开始爬取网页
    • 存储内容(Pipeline):设计管道存储爬取内容


    好的,基本流程既然确定了,那接下来就一步一步的完成就可以了。


    1.新建项目(Project)

    在空目录下按住Shift键右击,选择“在此处打开命令窗口”,输入一下命令:

    [plain]  view plain copy
    1. scrapy startproject tutorial  

    其中,tutorial为项目名称。

    可以看到将会创建一个tutorial文件夹,目录结构如下:

    [plain]  view plain copy
    1. tutorial/  
    2.     scrapy.cfg  
    3.     tutorial/  
    4.         __init__.py  
    5.         items.py  
    6.         pipelines.py  
    7.         settings.py  
    8.         spiders/  
    9.             __init__.py  
    10.             ...  



    下面来简单介绍一下各个文件的作用:

    • scrapy.cfg:项目的配置文件
    • tutorial/:项目的Python模块,将会从这里引用代码
    • tutorial/items.py:项目的items文件
    • tutorial/pipelines.py:项目的pipelines文件
    • tutorial/settings.py:项目的设置文件
    • tutorial/spiders/:存储爬虫的目录


    2.明确目标(Item)

    在Scrapy中,items是用来加载抓取内容的容器,有点像Python中的Dic,也就是字典,但是提供了一些额外的保护减少错误。

    一般来说,item可以用scrapy.item.Item类来创建,并且用scrapy.item.Field对象来定义属性(可以理解成类似于ORM的映射关系)。

    接下来,我们开始来构建item模型(model)。

    首先,我们想要的内容有:

    • 名称(name)
    • 链接(url)
    • 描述(description)


    修改tutorial目录下的items.py文件,在原本的class后面添加我们自己的class。

    因为要抓dmoz.org网站的内容,所以我们可以将其命名为DmozItem:

    [python]  view plain copy
    1. # Define here the models for your scraped items  
    2. #  
    3. # See documentation in:  
    4. # http://doc.scrapy.org/en/latest/topics/items.html  
    5.   
    6. from scrapy.item import Item, Field  
    7.   
    8. class TutorialItem(Item):  
    9.     # define the fields for your item here like:  
    10.     # name = Field()  
    11.     pass  
    12.   
    13. class DmozItem(Item):  
    14.     title = Field()  
    15.     link = Field()  
    16.     desc = Field()  

    刚开始看起来可能会有些看不懂,但是定义这些item能让你用其他组件的时候知道你的 items到底是什么。

    可以把Item简单的理解成封装好的类对象。


    3.制作爬虫(Spider)

    制作爬虫,总体分两步:先爬再取。

    也就是说,首先你要获取整个网页的所有内容,然后再取出其中对你有用的部分。

    3.1爬

    Spider是用户自己编写的类,用来从一个域(或域组)中抓取信息。

    他们定义了用于下载的URL列表、跟踪链接的方案、解析网页内容的方式,以此来提取items。

    要建立一个Spider,你必须用scrapy.spider.BaseSpider创建一个子类,并确定三个强制的属性:

    • name:爬虫的识别名称,必须是唯一的,在不同的爬虫中你必须定义不同的名字。
    • start_urls:爬取的URL列表。爬虫从这里开始抓取数据,所以,第一次下载的数据将会从这些urls开始。其他子URL将会从这些起始URL中继承性生成。
    • parse():解析的方法,调用的时候传入从每一个URL传回的Response对象作为唯一参数,负责解析并匹配抓取的数据(解析为item),跟踪更多的URL。

     

    这里可以参考宽度爬虫教程中提及的思想来帮助理解,教程传送:[Java] 知乎下巴第5集:使用HttpClient工具包和宽度爬虫。

    也就是把Url存储下来并依此为起点逐步扩散开去,抓取所有符合条件的网页Url存储起来继续爬取。



    下面我们来写第一只爬虫,命名为dmoz_spider.py,保存在tutorial\spiders目录下。

    dmoz_spider.py代码如下:

    [python]  view plain copy
    1. from scrapy.spider import Spider  
    2.   
    3. class DmozSpider(Spider):  
    4.     name = "dmoz"  
    5.     allowed_domains = ["dmoz.org"]  
    6.     start_urls = [  
    7.         "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",  
    8.         "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"  
    9.     ]  
    10.   
    11.     def parse(self, response):  
    12.         filename = response.url.split("/")[-2]  
    13.         open(filename, 'wb').write(response.body)  
    allow_domains是搜索的域名范围,也就是爬虫的约束区域,规定爬虫只爬取这个域名下的网页。

    从parse函数可以看出,将链接的最后两个地址取出作为文件名进行存储。

    然后运行一下看看,在tutorial目录下按住shift右击,在此处打开命令窗口,输入:

    [plain]  view plain copy
    1. scrapy crawl dmoz  

    运行结果如图:

    Python之网络爬虫完全教程_第32张图片

    报错了:

    UnicodeDecodeError: 'ascii' codec can't decode byte 0xb0 in position 1: ordinal not in range(128)

    运行第一个Scrapy项目就报错,真是命运多舛。

    应该是出了编码问题,谷歌了一下找到了解决方案:

    在python的Lib\site-packages文件夹下新建一个sitecustomize.py:

    [python]  view plain copy
    1. import sys    
    2. sys.setdefaultencoding('gb2312')    

    再次运行,OK,问题解决了,看一下结果:

    Python之网络爬虫完全教程_第33张图片

    最后一句INFO: Closing spider (finished)表明爬虫已经成功运行并且自行关闭了。

    包含 [dmoz]的行 ,那对应着我们的爬虫运行的结果。

    可以看到start_urls中定义的每个URL都有日志行。

    还记得我们的start_urls吗?

    http://www.dmoz.org/Computers/Programming/Languages/Python/Books
    http://www.dmoz.org/Computers/Programming/Languages/Python/Resources

    因为这些URL是起始页面,所以他们没有引用(referrers),所以在它们的每行末尾你会看到 (referer: )。

    在parse 方法的作用下,两个文件被创建:分别是 Books 和 Resources,这两个文件中有URL的页面内容。


    那么在刚刚的电闪雷鸣之中到底发生了什么呢?

    首先,Scrapy为爬虫的 start_urls属性中的每个URL创建了一个 scrapy.http.Request 对象 ,并将爬虫的parse 方法指定为回调函数。

    然后,这些 Request被调度并执行,之后通过parse()方法返回scrapy.http.Response对象,并反馈给爬虫。


    3.2取

    爬取整个网页完毕,接下来的就是的取过程了。

    光存储一整个网页还是不够用的。

    在基础的爬虫里,这一步可以用正则表达式来抓。

    在Scrapy里,使用一种叫做 XPath selectors的机制,它基于 XPath表达式。

    如果你想了解更多selectors和其他机制你可以查阅资料:点我点我


    这是一些XPath表达式的例子和他们的含义

    • /html/head/title: 选择HTML文档元素下面的 标签。</span></li> <li><span style="font-family:'Microsoft YaHei'; font-size:18px">/html/head/title/text(): 选择前面提到的<title> 元素下面的文本内容</span></li> <li><span style="font-family:'Microsoft YaHei'; font-size:18px">//td: 选择所有 <td> 元素</span></li> <li><span style="font-family:'Microsoft YaHei'; font-size:18px">//div[@class="mine"]: 选择所有包含 class="mine" 属性的div 标签元素</span></li> </ul> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">以上只是几个使用XPath的简单例子,但是实际上XPath非常强大。</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">可以参照W3C教程:点我点我。</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px"><br> </span></p> <span style="line-height:26px; font-family:'Microsoft YaHei'; font-size:18px">为了方便使用XPaths,Scrapy提供XPathSelector 类,有两种可以选择,HtmlXPathSelector(HTML数据解析)和XmlXPathSelector(XML数据解析)。<br> </span> <span style="font-family:Arial; font-size:14px; line-height:26px"></span> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">必须通过一个 Response 对象对他们进行实例化操作。</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">你会发现Selector对象展示了文档的节点结构。因此,第一个实例化的selector必与根节点或者是整个目录有关 。<br> </span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">在Scrapy里面,Selectors 有四种基础的方法</span><span style="font-family:'Microsoft YaHei'; font-size:18px"><span class="reference internal"><span class="xref py py-meth docutils literal"><span class="pre">(点击查看API文档):</span></span></span><span class="xref py py-meth docutils literal"><span class="pre"><br> </span></span></span></p> <ul style="font-family:Arial; font-size:14px; line-height:26px"> <li><span style="font-family:'Microsoft YaHei'; font-size:18px"><span class="xref py py-meth docutils literal"><span class="pre">xpath()</span></span>:返回一系列的selectors,每一个select表示一个xpath参数表达式选择的节点<span class="xref py py-meth docutils literal"><span class="pre"><br> </span></span></span></li> <li><span style="font-family:'Microsoft YaHei'; font-size:18px"><span class="xref py py-meth docutils literal"><span class="pre">css()</span></span>:返回一系列的selectors,每一个select表示一个css参数表达式选择的节点<span class="xref py py-meth docutils literal"><span class="pre"><br> </span></span></span></li> <li><span style="font-family:'Microsoft YaHei'; font-size:18px"><span class="xref py py-meth docutils literal"><span class="pre">extract()</span></span>:返回一个unicode字符串,为选中的数据<span class="xref py py-meth docutils literal"><span class="pre"><br> </span></span></span></li> <li><span style="font-family:'Microsoft YaHei'; font-size:18px"><span class="xref py py-meth docutils literal"><span class="pre">re()</span></span>:返回一串一个unicode字符串,为使用正则表达式抓取出来的内容</span></li> </ul> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <br> </p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px"><strong>3.3xpath实验</strong><br> </span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">下面我们在Shell里面尝试一下Selector的用法。</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">实验的网址:http://www.dmoz.org/Computers/Programming/Languages/Python/Books/<br> </span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px"><a href="http://img.e-com-net.com/image/info8/232baabb95584158ac4f57c881d67279.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/232baabb95584158ac4f57c881d67279.jpg" alt="Python之网络爬虫完全教程_第34张图片" style="border:none; max-width:100%;border:1px solid black;" width="650" height="293"></a><br> </span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px"><br> </span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">熟悉完了实验的小白鼠,接下来就是用Shell爬取网页了。</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">进入到项目的顶层目录,也就是第一层tutorial文件夹下,在cmd中输入:</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px"></span></p> <div class="dp-highlighter bg_plain" style="font-family:Consolas,'Courier New',Courier,mono,serif; width:936.53125px; overflow:auto; padding-top:1px; line-height:26px; margin:18px 0px!important; background-color:rgb(231,229,220)"> <div class="bar" style="padding-left:45px"> <div class="tools" style="padding:3px 8px 10px 10px; font-size:9px; line-height:normal; font-family:Verdana,Geneva,Arial,Helvetica,sans-serif; color:silver; border-left-width:3px; border-left-style:solid; border-left-color:rgb(108,226,108); background-color:rgb(248,248,248)"> <strong>[plain]</strong>  view plain copy <div style="position:absolute; left:441px; top:6184px; width:18px; height:18px; z-index:99"> </div> </div> </div> <ol start="1" style="padding:0px; border:none; list-style-position:initial; color:rgb(92,92,92); margin:0px 0px 1px 45px!important; background-color:rgb(255,255,255)"> <li class="alt" style="border-style:none none none solid; border-left-width:3px; border-left-color:rgb(108,226,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> <span style="margin:0px; padding:0px; border:none; color:black; background-color:inherit"><span style="margin:0px; padding:0px; border:none; background-color:inherit">scrapy shell http://www.dmoz.org/Computers/Programming/Languages/Python/Books/  </span></span></li> </ol> </div> <br style="font-family:Arial; font-size:14px; line-height:26px"> <span style="line-height:26px; font-family:'Microsoft YaHei'; font-size:18px">回车后可以看到如下的内容:</span> <span style="font-family:Arial; font-size:14px; line-height:26px"></span> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> </p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px"><a href="http://img.e-com-net.com/image/info8/2b517a785a264ec891984ca0864cff99.png" target="_blank"><img src="http://img.e-com-net.com/image/info8/2b517a785a264ec891984ca0864cff99.png" alt="Python之网络爬虫完全教程_第35张图片" style="border:none; max-width:100%;border:1px solid black;" width="677" height="443"></a></span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px"></span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <br> </p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">在Shell载入后,你将获得response回应,存储在本地变量 response中。</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">所以如果你输入response.body,你将会看到response的body部分,也就是抓取到的页面内容:</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <a href="http://img.e-com-net.com/image/info8/ba70f9937be147008d0e8b7a8411a428.png" target="_blank"><img src="http://img.e-com-net.com/image/info8/ba70f9937be147008d0e8b7a8411a428.png" alt="Python之网络爬虫完全教程_第36张图片" style="border:none; max-width:100%;border:1px solid black;" width="677" height="443"></a><br> </p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">或者输入response.headers 来查看它的 header部分:</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <a href="http://img.e-com-net.com/image/info8/243c9a40ecb34544af37d072a52b2bd0.png" target="_blank"><img src="http://img.e-com-net.com/image/info8/243c9a40ecb34544af37d072a52b2bd0.png" alt="Python之网络爬虫完全教程_第37张图片" style="border:none; max-width:100%;border:1px solid black;" width="677" height="443"></a><br> </p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <br> </p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">现在就像是一大堆沙子握在手里,里面藏着我们想要的金子,所以下一步,就是用筛子摇两下,把杂质出去,选出关键的内容。</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">selector就是这样一个筛子。</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">在旧的版本中,Shell实例化两种selectors,一个是解析HTML的 hxs 变量,一个是解析XML 的 xxs 变量。</span><span style="font-family:'Microsoft YaHei'; font-size:18px"><br> </span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">而现在的Shell为我们准备好的selector对象,sel,可以根据返回的数据类型自动选择最佳的解析方案(XML or HTML)。</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">然后我们来捣弄一下!~</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">要彻底搞清楚这个问题,首先先要知道,抓到的页面到底是个什么样子。</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">比如,我们要抓取网页的标题,也就是<title>这个标签:</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <a href="http://img.e-com-net.com/image/info8/b54b50ad98984990a58afcb2369cbe93.png" target="_blank"><img src="http://img.e-com-net.com/image/info8/b54b50ad98984990a58afcb2369cbe93.png" alt="" style="border:none; max-width:100%" width="465" height="71"></a><br> </p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <span style="font-family:'Microsoft YaHei'; font-size:18px">可以输入:</span></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> </p> <div class="dp-highlighter bg_python" style="font-family:Consolas,'Courier New',Courier,mono,serif; width:936.53125px; overflow:auto; padding-top:1px; line-height:26px; margin:18px 0px!important; background-color:rgb(231,229,220)"> <div class="bar" style="padding-left:45px"> </div> </div> </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1187289708271607808"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(学习碎片)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1881486146245029888.htm" title="告别繁琐!使用AI代码生成器ScriptEcho快速构建WebSocket实时应用" target="_blank">告别繁琐!使用AI代码生成器ScriptEcho快速构建WebSocket实时应用</a> <span class="text-muted"></span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>WebSocket实时应用,以其低延迟、高效率的特点,在实时聊天、在线游戏、股票交易等领域发挥着越来越重要的作用。然而,对于新手开发者来说,构建一个功能完善的WebSocket应用却并非易事。复杂的代码编写、繁琐的后端接口对接以及漫长的调试测试过程,往往成为入门学习的巨大挑战。幸运的是,现在有了AI代码生成器ScriptEcho,它能够显著简化开发流程,帮助你快速构建高质量的WebSocket应用</div> </li> <li><a href="/article/1881479589369278464.htm" title="咱们继续学Java——高级篇 第一百九十八篇:之Java 2D中的区域与笔划知识详解" target="_blank">咱们继续学Java——高级篇 第一百九十八篇:之Java 2D中的区域与笔划知识详解</a> <span class="text-muted">一杯年华@编程空间</span> <a class="tag" taget="_blank" href="/search/%E5%92%B1%E4%BB%AC%E7%BB%A7%E7%BB%AD%E5%AD%A6java%E9%AB%98%E7%BA%A7%E7%AF%87/1.htm">咱们继续学java高级篇</a><a class="tag" taget="_blank" href="/search/struts/1.htm">struts</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/java-ee/1.htm">java-ee</a><a class="tag" taget="_blank" href="/search/jetty/1.htm">jetty</a><a class="tag" taget="_blank" href="/search/junit/1.htm">junit</a><a class="tag" taget="_blank" href="/search/log4j/1.htm">log4j</a><a class="tag" taget="_blank" href="/search/servlet/1.htm">servlet</a> <div>咱们继续学Java——高级篇第一百九十八篇:之Java2D中的区域与笔划知识详解在Java的学习征程中,每一个知识点都是我们积累经验、提升能力的基石。我写这篇博客的目的,就是希望能与各位一同探索Java编程的奇妙世界,共同在这个领域中取得进步。今天,我们将聚焦于Java2D中的区域和笔划相关知识,深入了解这些概念和操作,相信这会让你在图形绘制方面有更多的技巧和方法。Path2D类的方法介绍java</div> </li> <li><a href="/article/1881478833408897024.htm" title="PyTorch 基础数据集:从理论到实践的深度学习基石" target="_blank">PyTorch 基础数据集:从理论到实践的深度学习基石</a> <span class="text-muted">那年一路北</span> <a class="tag" taget="_blank" href="/search/Pytorch%E7%90%86%E8%AE%BA%2B%E5%AE%9E%E8%B7%B5/1.htm">Pytorch理论+实践</a><a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/1.htm">深度学习</a><a class="tag" taget="_blank" href="/search/pytorch/1.htm">pytorch</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a> <div>一、引言深度学习作为当今人工智能领域的核心技术,在图像识别、自然语言处理、语音识别等众多领域取得了令人瞩目的成果。而在深度学习的体系中,数据扮演着举足轻重的角色,它是模型训练的基础,如同建筑的基石,决定了模型的性能和泛化能力。PyTorch作为当下最流行的深度学习框架之一,为开发者提供了丰富且强大的工具来处理数据集。本文将深入探讨PyTorch中的基础数据集,从深度学习中数据的重要性出发,详细介绍</div> </li> <li><a href="/article/1881474666174935040.htm" title="新星计划Day11【数据结构与算法】 排序算法2" target="_blank">新星计划Day11【数据结构与算法】 排序算法2</a> <span class="text-muted">京与旧铺</span> <a class="tag" taget="_blank" href="/search/java%E5%AD%A6%E4%B9%A0/1.htm">java学习</a><a class="tag" taget="_blank" href="/search/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/1.htm">排序算法</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a> <div>新星计划Day11【数据结构与算法】排序算法2‍博客主页:京与旧铺的博客主页✨欢迎关注点赞收藏⭐留言✒本文由京与旧铺原创,csdn首发!系列专栏:java学习参考网课:尚硅谷首发时间:2022年5月13日你做三四月的事,八九月就会有答案,一起加油吧如果觉得博主的文章还不错的话,请三连支持一下博主哦最后的话,作者是一个新人,在很多方面还做的不好,欢迎大佬指正,一起学习哦,冲冲冲推荐一款模拟面试、刷题</div> </li> <li><a href="/article/1881472398792912896.htm" title="React Native 介绍" target="_blank">React Native 介绍</a> <span class="text-muted">王睿丶</span> <a class="tag" taget="_blank" href="/search/%E8%B5%84%E8%AE%AF%E7%9C%8B%E7%82%B9/1.htm">资讯看点</a><a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/Native/1.htm">Native</a><a class="tag" taget="_blank" href="/search/%E7%A7%BB%E5%8A%A8%E5%BC%80%E5%8F%91/1.htm">移动开发</a><a class="tag" taget="_blank" href="/search/%E8%B7%A8%E5%B9%B3%E5%8F%B0/1.htm">跨平台</a><a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/%E7%8E%8B%E7%9D%BF%E4%B8%B6/1.htm">王睿丶</a> <div>文章目录一丶ReactNative惊喜二丶ReactNative简介三丶ReactNative特性四丶ReactNative优点五丶ReactNative局限性六丶构建最简单的应用七丶学习资料一丶ReactNative惊喜ReactNative是一个使用JavaScript和React来编写跨终端移动应用(Android或IOS)的一种解决方案这句话是什么意思呢?即使你不懂如何使用Java或Kot</div> </li> <li><a href="/article/1881464959280410624.htm" title="收藏!Python常用的第三方模块,你知道几个呢?" target="_blank">收藏!Python常用的第三方模块,你知道几个呢?</a> <span class="text-muted">Python子木_</span> <a class="tag" taget="_blank" href="/search/Python%E5%85%A5%E9%97%A8/1.htm">Python入门</a><a class="tag" taget="_blank" href="/search/Python%E5%AD%A6%E4%B9%A0/1.htm">Python学习</a><a class="tag" taget="_blank" href="/search/Python%E9%9B%B6%E5%9F%BA%E7%A1%80/1.htm">Python零基础</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/pandas/1.htm">pandas</a><a class="tag" taget="_blank" href="/search/python%E6%95%99%E7%A8%8B/1.htm">python教程</a><a class="tag" taget="_blank" href="/search/python%E5%9F%BA%E7%A1%80/1.htm">python基础</a><a class="tag" taget="_blank" href="/search/python%E5%AD%A6%E4%B9%A0/1.htm">python学习</a><a class="tag" taget="_blank" href="/search/python%E5%85%A5%E9%97%A8/1.htm">python入门</a><a class="tag" taget="_blank" href="/search/%E9%9D%92%E5%B0%91%E5%B9%B4%E7%BC%96%E7%A8%8B/1.htm">青少年编程</a> <div>作为一种流行的编程语言,拥有丰富的第三方模块,这些模块极大地扩展了的功能,使得各种开发任务变得更加高效和便捷.本文将介绍几种常用的第三方模块,提供示例展示,并对它们进行分类,以帮助读者更好地理解和使用这些工具.这里插播一条粉丝福利,如果你正在学习Python或者有计划学习Python,想要突破自我,对未来十分迷茫的,可以点击这里获取最新的Python学习资料和学习路线规划(免费分享,记得关注)1.</div> </li> <li><a href="/article/1881462943099449344.htm" title="Day_1 数据结构与算法&LeetCode入门及攻略" target="_blank">Day_1 数据结构与算法&LeetCode入门及攻略</a> <span class="text-muted">Finger-Von-Frings</span> <a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a><a class="tag" taget="_blank" href="/search/leetcode/1.htm">leetcode</a> <div>数据结构与算法学习目的:我们学习算法和数据结构,是为了学会在编程中从时间复杂度、空间复杂度方面考虑解决方案,训练自己的逻辑思维,从而写出高质量的代码,以此提升自己的编程技能,获取更高的工作回报。数据结构定义:数据结构(DataStructure)指的是带有结构特性的数据元素的集合。学习的目的:为了帮助我们了解和掌握计算机中的数据是以何种方式进行组织、存储的。Q1:何为结构特性?所谓结构特性,指的是</div> </li> <li><a href="/article/1881460796827955200.htm" title="动态内存管理" target="_blank">动态内存管理</a> <span class="text-muted">ulias212</span> <a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/c%E8%AF%AD%E8%A8%80/1.htm">c语言</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>在了解和学习之前,我们需要了解为什么要有动态内存管理?程序运行时需要动态分配内存,而系统提供的内存有限程序运行时需要频繁地分配和释放内存,降低系统的内存利用率程序运行时需要处理大量的内存,如字符串、数组、结构体等malloc和free函数#includevoid*malloc(size_tsize)我们可以通过如此的操作来分配内存。参数的单位是字节(size_t),如果申请内存成功返回起始地址,反</div> </li> <li><a href="/article/1881460418799529984.htm" title="【深度学习】Pytorch:导入导出模型参数" target="_blank">【深度学习】Pytorch:导入导出模型参数</a> <span class="text-muted">T0uken</span> <a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/1.htm">深度学习</a><a class="tag" taget="_blank" href="/search/pytorch/1.htm">pytorch</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a> <div>PyTorch是深度学习领域中广泛使用的框架,熟练掌握其模型参数的管理对于模型训练、推理以及部署非常重要。本文将全面讲解PyTorch中关于模型参数的操作,包括如何导出、导入以及如何下载模型参数。什么是模型参数模型参数是指深度学习模型中需要通过训练来优化的变量,如神经网络中的权重和偏置。这些参数存储在PyTorch的torch.nn.Module对象中,通过以下方式访问:importtorchim</div> </li> <li><a href="/article/1881456891754770432.htm" title="matlab程序代编程写做代码图像处理BP神经网络机器深度学习python" target="_blank">matlab程序代编程写做代码图像处理BP神经网络机器深度学习python</a> <span class="text-muted">matlabgoodboy</span> <a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/1.htm">深度学习</a><a class="tag" taget="_blank" href="/search/matlab/1.htm">matlab</a><a class="tag" taget="_blank" href="/search/%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86/1.htm">图像处理</a> <div>1.安装必要的库首先,确保你已经安装了必要的Python库。如果没有安装,请运行以下命令:bash复制代码pipinstallnumpymatplotlibtensorflowopencv-python2.图像预处理我们将使用OpenCV来加载和预处理图像数据。假设你有一个图像数据集,每个类别的图像存放在单独的文件夹中。python复制代码importosimportcv2importnumpya</div> </li> <li><a href="/article/1881456638766936064.htm" title="Kubernetes架构原则和对象设计(二)" target="_blank">Kubernetes架构原则和对象设计(二)</a> <span class="text-muted">grahamzhu</span> <a class="tag" taget="_blank" href="/search/%E4%BA%91%E5%8E%9F%E7%94%9F%E5%AD%A6%E4%B9%A0%E4%B8%93%E6%A0%8F/1.htm">云原生学习专栏</a><a class="tag" taget="_blank" href="/search/kubernetes/1.htm">kubernetes</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a><a class="tag" taget="_blank" href="/search/%E5%AE%B9%E5%99%A8/1.htm">容器</a><a class="tag" taget="_blank" href="/search/%E9%9B%86%E7%BE%A4%E6%90%AD%E5%BB%BA/1.htm">集群搭建</a><a class="tag" taget="_blank" href="/search/API%E8%AE%BE%E8%AE%A1/1.htm">API设计</a><a class="tag" taget="_blank" href="/search/%E4%BA%91%E8%AE%A1%E7%AE%97/1.htm">云计算</a><a class="tag" taget="_blank" href="/search/kubelet/1.htm">kubelet</a> <div>云原生学习路线导航页(持续更新中)kubernetes学习系列快捷链接Kubernetes架构原则和对象设计(一)Kubernetes常见问题解答本文从云计算架构发展入手,详细分析了kubernetes的生态系统、设计理念、分层架构、API设计原则、架构设计原则等,并介绍了使用kubelet+staticPod拉起集群的过程1.云计算的传统分类云计算出现之前,对于任何企业,想要搭建自己的服务,需要</div> </li> <li><a href="/article/1881452977282150400.htm" title="Spring Task定时任务的基础使用" target="_blank">Spring Task定时任务的基础使用</a> <span class="text-muted">Bailey395</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a> <div>SpringTask的使用就分为3步骤:1.在pom.xml中导入对应的依赖2.自定义定时任务累3.在启动类中添加对应的注解学习之前我们先学习一下cron表达式:在我们使用调度任务技术的时候,特别是调度框架,里面都支持使用日历的方式来设置任务制定的时间、频率等,通常情况下都会使用cron表达式来表达cron表达式是一个字符串,用来设置定时规则,由七部分组成,每部分中间用空格隔开,每部分的含义如下表</div> </li> <li><a href="/article/1881451591349891072.htm" title="后端程序员基础篇(一) JAVA基础" target="_blank">后端程序员基础篇(一) JAVA基础</a> <span class="text-muted">菜鸡来咯</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>在以往的博客中,大部分讲解的是框架的基础框架和功能模块,对于想要从事Web开发的同学来说,框架和各个功能模块固然非常重要,但这些都是建立在你有深厚的基础之上的,一开始学习的重点应该放在基础上面,在有了深厚的地基之后,学习框架和各个功能模块再之后的微服务等各个架构才能举一反三,学习得更加透彻接下来以我的逻辑来简要说明一下Web应用的开发人员的学习之路,算是帮助目前还比较迷茫的同学。Java基础,Sq</div> </li> <li><a href="/article/1881451465009065984.htm" title="Python气象数据分析:风速预报订正、台风预报数据智能订正、机器学习预测风电场的风功率、浅水模型、预测ENSO等" target="_blank">Python气象数据分析:风速预报订正、台风预报数据智能订正、机器学习预测风电场的风功率、浅水模型、预测ENSO等</a> <span class="text-muted">小艳加油</span> <a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%B0%94%E7%A7%91%E5%AD%A6/1.htm">大气科学</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E6%B0%94%E8%B1%A1/1.htm">气象</a><a class="tag" taget="_blank" href="/search/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/1.htm">机器学习</a> <div>目录专题一Python和科学计算基础专题二机器学习和深度学习基础理论和实操专题三气象领域中的机器学习应用实例专题四气象领域中的深度学习应用实例更多应用Python是功能强大、免费、开源,实现面向对象的编程语言,在数据处理、科学计算、数学建模、数据挖掘和数据可视化方面具备优异的性能,这些优势使得Python在气象、海洋、地理、气候、水文和生态等地学领域的科研和工程项目中得到广泛应用。可以预见未来Py</div> </li> <li><a href="/article/1881451086766731264.htm" title="YOLOv8/YOLOv11使用web界面推理自己的模型,Gradio框架快速搭建" target="_blank">YOLOv8/YOLOv11使用web界面推理自己的模型,Gradio框架快速搭建</a> <span class="text-muted">挂科边缘</span> <a class="tag" taget="_blank" href="/search/YOLOv8%E6%94%B9%E8%BF%9B/1.htm">YOLOv8改进</a><a class="tag" taget="_blank" href="/search/YOLO/1.htm">YOLO</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/1.htm">计算机视觉</a><a class="tag" taget="_blank" href="/search/%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B/1.htm">目标检测</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>前言Gradio是一个开源Python库,用于快速构建和共享机器学习模型的Web界面。开发者可以通过简单的Python代码将机器学习模型封装成交互式应用,无需复杂的设置即可在浏览器中使用自己训练好模型。接下来教你使用Gradio框架构建一个简单Web界面推理YOLOv8/YOLOv11模型。话不多说上检测结果:一、YOLOv8/YOLOv11源码下载YOLOv8源码下载:官网打不开的话,从我的网盘</div> </li> <li><a href="/article/1881439491806261248.htm" title="自学 python 中的异步编程 asyncio (五):asyncio 与 线程thread" target="_blank">自学 python 中的异步编程 asyncio (五):asyncio 与 线程thread</a> <span class="text-muted">Eaton5959</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>自学python中的异步编程asyncio(一):学习基本概念自学python中的异步编程asyncio(二):asyncio模块与核心组件自学python中的异步编程asyncio(三):asyncio实现基本异步编程自学python中的异步编程asyncio(四):基本的异步IO编程自学python中的异步编程asyncio(五):asyncio与线程thread自学python中的异步编程a</div> </li> <li><a href="/article/1881438733086027776.htm" title="iPhone手机桌面必备:好用的便签/效率/美化/学习/生活工具" target="_blank">iPhone手机桌面必备:好用的便签/效率/美化/学习/生活工具</a> <span class="text-muted">lee54621</span> <a class="tag" taget="_blank" href="/search/%E6%99%BA%E8%83%BD%E6%89%8B%E6%9C%BA/1.htm">智能手机</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E7%94%9F%E6%B4%BB/1.htm">生活</a> <div>是不是总觉得自己的iPhone手机桌面不够酷炫、不够实用?看着千篇一律的布局,是不是觉得缺了点什么?别担心,今天就给大家分享一波iPhone手机桌面必备的好用App,让你的手机瞬间提升格调,实用性拉满,无论是学习、工作还是娱乐,都能得心应手,轻松拿捏,赶紧跟着我一起探索这些宝藏应用吧!》》效率提升类敬业签:可以和鸿蒙安卓电脑共享数据的云便签,集合便签、清单、提醒事项、日历、云盘、翻译、语音转文字、</div> </li> <li><a href="/article/1881437587894235136.htm" title="深度学习笔记——模型部署" target="_blank">深度学习笔记——模型部署</a> <span class="text-muted">好评笔记</span> <a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/1.htm">深度学习笔记</a><a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/1.htm">深度学习</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/transformer/1.htm">transformer</a><a class="tag" taget="_blank" href="/search/%E6%A8%A1%E5%9E%8B%E9%83%A8%E7%BD%B2/1.htm">模型部署</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%A8%A1%E5%9E%8B%E9%83%A8%E7%BD%B2/1.htm">大模型部署</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%A8%A1%E5%9E%8B/1.htm">大模型</a> <div>大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本文简要概括模型部署的知识点,包括步骤和部署方式。文章目录模型部署模型部署的关键步骤常见的模型部署方式优势与挑战总结边缘端部署方案总结历史文章机器学习深度学习模型部署模型部署是指将训练好的机器学习或深度学习模型集成到生产环境中,使其能够在实际应用中处理实时数据和提供预测服务。模型部署的流程涉及模型的封装、部署环境的选择、部</div> </li> <li><a href="/article/1881437587281866752.htm" title="探索泰坦尼克号生存分类数据集:机器学习与数据分析的完美起点" target="_blank">探索泰坦尼克号生存分类数据集:机器学习与数据分析的完美起点</a> <span class="text-muted">岑童嵘</span> <div>探索泰坦尼克号生存分类数据集:机器学习与数据分析的完美起点【下载地址】泰坦尼克号生存分类数据集本仓库提供了一个经典的机器学习数据集——泰坦尼克号生存分类数据集。该数据集包含两个CSV文件:训练集和测试集。数据集主要用于训练和评估机器学习模型,以预测泰坦尼克号乘客的生存情况项目地址:https://gitcode.com/open-source-toolkit/35561项目介绍泰坦尼克号生存分类数</div> </li> <li><a href="/article/1881435819454033920.htm" title="k8s_CKA考试_学习笔记" target="_blank">k8s_CKA考试_学习笔记</a> <span class="text-muted">bq_o_pd</span> <a class="tag" taget="_blank" href="/search/kubernetes/1.htm">kubernetes</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E5%AE%B9%E5%99%A8/1.htm">容器</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a> <div>k3s默认无法使用docker,导入docker的镜像加载到k3s中[root@worker1php]#k3scrictlimagesIMAGETAGIMAGEIDSIZEdocker.io/library/busyboxlatest9211bbaa0dbd62.23MBdocker.io/library/nginx1.7.935d28df486f6139.9MBdocker.io/library</div> </li> <li><a href="/article/1881434805468459008.htm" title="NextJs - 服务端组件如何拿到当前页面的URL或者参数" target="_blank">NextJs - 服务端组件如何拿到当前页面的URL或者参数</a> <span class="text-muted">Zong_0915</span> <a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/NextJs/1.htm">NextJs</a> <div>NextJs-服务端组件如何拿到当前页面的URL或者参数前言一.NextJs如何拿到当前页面URL二.NextJs拿URL参数的两种方式前言NextJs中,如果你是服务端组件,并且是App路由模式,如果想拿到当前URL,我们只能通过中间件获取,并通过header来实现交互。想再学习下中间件的可以参考我的这篇文章:NextJs初级篇-安装|路由|中间件一.NextJs如何拿到当前页面URL我们编写根</div> </li> <li><a href="/article/1881431526986543104.htm" title="基于Python机器学习、深度学习技术提升气象、海洋、水文领域实践应用" target="_blank">基于Python机器学习、深度学习技术提升气象、海洋、水文领域实践应用</a> <span class="text-muted">KY_chenzhao</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/1.htm">机器学习</a><a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/1.htm">深度学习</a><a class="tag" taget="_blank" href="/search/%E6%B0%94%E8%B1%A1/1.htm">气象</a> <div>1.背景与目标ENSO(ElNiño-SouthernOscillation)是全球气候系统中最显著的年际变率现象之一,对全球气候、农业、渔业等有着深远的影响。准确预测ENSO事件的发生和发展对于减灾防灾具有重要意义。近年来,深度学习技术在气象领域得到了广泛应用,其中长短期记忆网络(LSTM)因其在处理时间序列数据方面的优势,被广泛用于ENSO预测。2.数据准备数据来源包括NOAA(美国国家海洋和</div> </li> <li><a href="/article/1881431022457909248.htm" title="PySide6 GUI 学习笔记——Python文件编译打包" target="_blank">PySide6 GUI 学习笔记——Python文件编译打包</a> <span class="text-muted">Humbunklung</span> <a class="tag" taget="_blank" href="/search/PySide6/1.htm">PySide6</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/1.htm">学习笔记</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>前面编写的软件工具都必须运行在Python环境中,且通过命令行的方式运行,通过Python打包工具,我们可以把.py文件封装成对应平台的运行文件,供用户执行。常见Python打包工具工具简介官网/文档地址py2exe将Python脚本转换为Windows可执行文件https://www.py2exe.orgcx_Freeze跨平台的Python打包工具,它可以将Python脚本打包为可执行文件或动</div> </li> <li><a href="/article/1881429636676644864.htm" title="AWS学习笔记——Chapter5 Identity and Access Management and Security on AWS" target="_blank">AWS学习笔记——Chapter5 Identity and Access Management and Security on AWS</a> <span class="text-muted">坚果壳er</span> <a class="tag" taget="_blank" href="/search/AWS%E5%AD%A6%E4%B9%A0/1.htm">AWS学习</a> <div>前注:学习书籍IndexIdentityandAccessManagementandSecurityonAWS1.Authentication(认证)2.Authorization(授权)3.Auditing(审核)4.Typesofsecuritycredentials(安全凭证的类型)5.Users6.Groups7.Roles8.IAMHierarchyofPrivileges9.IAMBe</div> </li> <li><a href="/article/1881429130726141952.htm" title="R语言的软件工程" target="_blank">R语言的软件工程</a> <span class="text-muted">BinaryBardC</span> <a class="tag" taget="_blank" href="/search/%E5%8C%85%E7%BD%97%E4%B8%87%E8%B1%A1/1.htm">包罗万象</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>R语言的软件工程1.引言随着数据科学的快速发展,R语言作为一种统计计算和图形绘制的编程语言,其在数据分析、可视化以及机器学习等领域的应用日益广泛。尽管R语言在数据处理上有其独特的优势,但要将其运用于大型项目和商业应用中,就需要遵循软件工程的原则。本篇文章将探讨R语言在软件工程中的应用,主要涵盖软件开发生命周期、代码规范、版本控制、测试和文档等方面。2.软件开发生命周期软件开发生命周期(SDLC)是</div> </li> <li><a href="/article/1881427490677780480.htm" title="《数据库学习之旅:探索数据的奥秘》" target="_blank">《数据库学习之旅:探索数据的奥秘》</a> <span class="text-muted">2301_82161368</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a> <div>在当今数字化的时代,数据库已成为信息管理和处理的核心基础设施。通过对数据库的学习和实践,我获得了许多宝贵的经验和深刻的认识。数据库就如同一座巨大的数据城堡,它有着严谨的结构和规则,却又充满了无限的可能。一开始,理解数据库的基本概念和原理并非易事,但随着逐步深入的学习,我渐渐揭开了它神秘的面纱。关系型数据库的表结构设计让我体会到了数据规划的重要性。合理地划分表、确定字段以及建立正确的关联关系,能够极</div> </li> <li><a href="/article/1881426735480762368.htm" title="ChatGPT Canvas:开启AI编程新纪元——你的AI代码生成器来了!" target="_blank">ChatGPT Canvas:开启AI编程新纪元——你的AI代码生成器来了!</a> <span class="text-muted"></span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>OpenAI近日宣布ChatGPTCanvas全面开放,并带来了两项重磅更新:直接运行Python代码和整合GPTs生态系统。这意味着,即使你不是专业的程序员,也能轻松体验编程的乐趣,并利用AI的力量创造出更多可能性。这对于想要学习编程或提高工作效率的用户来说,无疑是一个巨大的福音。这篇文章将深入探讨这两项更新,并展望ChatGPTCanvas的未来发展。直接运行Python代码:降低编程门槛,释</div> </li> <li><a href="/article/1881425979176448000.htm" title="Python中的Pipeline快速教学、" target="_blank">Python中的Pipeline快速教学、</a> <span class="text-muted">Coding Is Fun</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>在Python中,Pipeline通常指的是机器学习工作流中的流水线,尤其是在使用scikit-learn库时。Pipeline允许你将多个数据处理步骤和模型训练步骤串联起来,形成一个有序的工作流程。这不仅使代码更简洁,还能确保在训练和预测时一致的数据处理。以下是一个快速教学,帮助你掌握Python中Pipeline的核心概念和使用方法。目录安装和导入必要的库Pipeline的基本概念创建一个简单</div> </li> <li><a href="/article/1881423451332341760.htm" title="Markdown学习笔记" target="_blank">Markdown学习笔记</a> <span class="text-muted">exm-zem</span> <a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a> <div>Markdown学习笔记——你好世界Markdown标题Markdown标题的两种格式:1、使用=和-来建立一个一级和二级标题:一级标题=================二级标题-----------------我展示的是一级标题我展示的是二级标题2、使用#号可以标记1-6级标题:#一级标题##二级标题###三级标题####四级标题#####五级标题######六级标题一级标题二级标题三级标题四级</div> </li> <li><a href="/article/1881411325201018880.htm" title="Docker使用 使用Dockerfile来创建镜像" target="_blank">Docker使用 使用Dockerfile来创建镜像</a> <span class="text-muted">BILLY BILLY</span> <a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E5%BF%85%E5%A4%87%E5%B7%A5%E5%85%B7/1.htm">开发必备工具</a><a class="tag" taget="_blank" href="/search/docker/1.htm">docker</a><a class="tag" taget="_blank" href="/search/%E5%AE%B9%E5%99%A8/1.htm">容器</a> <div>本篇文章主要介绍了Docker使用Dockerfile来创建镜像,本文学习Dcokerfile的基本命令,并且创建一个支持ssh服务的镜像.1.Dockerfile1.1基本案例基本案例dockerfile可以说是docker的描述符,该文件定义了docker镜像的所能拥有哪些东西.基本格式如下:第一行指定该镜像基于的基础镜像(必须)FROMjava:8维护者信息MAINTAINERqudingn</div> </li> <li><a href="/article/88.htm" title="ztree设置禁用节点" target="_blank">ztree设置禁用节点</a> <span class="text-muted">3213213333332132</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/ztree/1.htm">ztree</a><a class="tag" taget="_blank" href="/search/json/1.htm">json</a><a class="tag" taget="_blank" href="/search/setDisabledNode/1.htm">setDisabledNode</a><a class="tag" taget="_blank" href="/search/Ajax/1.htm">Ajax</a> <div>ztree设置禁用节点的时候注意,当使用ajax后台请求数据,必须要设置为同步获取数据,否者会获取不到节点对象,导致设置禁用没有效果。 $(function(){ showTree(); setDisabledNode(); }); </div> </li> <li><a href="/article/215.htm" title="JVM patch by Taobao" target="_blank">JVM patch by Taobao</a> <span class="text-muted">bookjovi</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/HotSpot/1.htm">HotSpot</a> <div>在网上无意中看到淘宝提交的hotspot patch,共四个,有意思,记录一下。   7050685:jsdbproc64.sh has a typo in the package name 7058036:FieldsAllocationStyle=2 does not work in 32-bit VM 7060619:C1 should respect inline and</div> </li> <li><a href="/article/342.htm" title="将session存储到数据库中" target="_blank">将session存储到数据库中</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/session/1.htm">session</a> <div>CREATE TABLE sessions ( id CHAR(32) NOT NULL, data TEXT, last_accessed TIMESTAMP NOT NULL, PRIMARY KEY (id) );   <?php /** * Created by PhpStorm. * User: michaeldu * Date</div> </li> <li><a href="/article/469.htm" title="Vector" target="_blank">Vector</a> <span class="text-muted">171815164</span> <a class="tag" taget="_blank" href="/search/vector/1.htm">vector</a> <div>public Vector<CartProduct> delCart(Vector<CartProduct> cart, String id) { for (int i = 0; i < cart.size(); i++) { if (cart.get(i).getId().equals(id)) { cart.remove(i); </div> </li> <li><a href="/article/596.htm" title="各连接池配置参数比较" target="_blank">各连接池配置参数比较</a> <span class="text-muted">g21121</span> <a class="tag" taget="_blank" href="/search/%E8%BF%9E%E6%8E%A5%E6%B1%A0/1.htm">连接池</a> <div>        排版真心费劲,大家凑合看下吧,见谅~     Druid DBCP C3P0 Proxool 数据库用户名称 Username Username User   数据库密码 Password Password Password   驱动名</div> </li> <li><a href="/article/723.htm" title="[简单]mybatis insert语句添加动态字段" target="_blank">[简单]mybatis insert语句添加动态字段</a> <span class="text-muted">53873039oycg</span> <a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a> <div>      mysql数据库,id自增,配置如下:       <insert id="saveTestTb" useGeneratedKeys="true" keyProperty="id" parameterType=&</div> </li> <li><a href="/article/850.htm" title="struts2拦截器配置" target="_blank">struts2拦截器配置</a> <span class="text-muted">云端月影</span> <a class="tag" taget="_blank" href="/search/struts2%E6%8B%A6%E6%88%AA%E5%99%A8/1.htm">struts2拦截器</a> <div>struts2拦截器interceptor的三种配置方法 方法1. 普通配置法 <struts>     <package name="struts2" extends="struts-default">         &</div> </li> <li><a href="/article/977.htm" title="IE中页面不居中,火狐谷歌等正常" target="_blank">IE中页面不居中,火狐谷歌等正常</a> <span class="text-muted">aijuans</span> <a class="tag" taget="_blank" href="/search/IE%E4%B8%AD%E9%A1%B5%E9%9D%A2%E4%B8%8D%E5%B1%85%E4%B8%AD/1.htm">IE中页面不居中</a> <div>问题是首页在火狐、谷歌、所有IE中正常显示,列表页的页面在火狐谷歌中正常,在IE6、7、8中都不中,觉得可能那个地方设置的让IE系列都不认识,仔细查看后发现,列表页中没写HTML模板部分没有添加DTD定义,就是<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3</div> </li> <li><a href="/article/1104.htm" title="String,int,Integer,char 几个类型常见转换" target="_blank">String,int,Integer,char 几个类型常见转换</a> <span class="text-muted">antonyup_2006</span> <a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a> <div>如何将字串 String 转换成整数 int? int i = Integer.valueOf(my_str).intValue(); int i=Integer.parseInt(str); 如何将字串 String 转换成Integer ? Integer integer=Integer.valueOf(str); 如何将整数 int 转换成字串 String ? 1.</div> </li> <li><a href="/article/1231.htm" title="PL/SQL的游标类型" target="_blank">PL/SQL的游标类型</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/%E6%98%BE%E7%A4%BA%E6%B8%B8%E6%A0%87%28%E9%9D%99%E6%80%81%E6%B8%B8%E6%A0%87%29/1.htm">显示游标(静态游标)</a><a class="tag" taget="_blank" href="/search/%E9%9A%90%E5%BC%8F%E6%B8%B8%E6%A0%87/1.htm">隐式游标</a><a class="tag" taget="_blank" href="/search/%E6%B8%B8%E6%A0%87%E7%9A%84%E6%9B%B4%E6%96%B0%E5%92%8C%E5%88%A0%E9%99%A4/1.htm">游标的更新和删除</a><a class="tag" taget="_blank" href="/search/%25rowtype/1.htm">%rowtype</a><a class="tag" taget="_blank" href="/search/ref%E6%B8%B8%E6%A0%87%28%E5%8A%A8%E6%80%81%E6%B8%B8%E6%A0%87%29/1.htm">ref游标(动态游标)</a> <div>游标是oracle中的一个结果集,用于存放查询的结果;   PL/SQL中游标的声明; 1,声明游标 2,打开游标(默认是关闭的); 3,提取数据 4,关闭游标     注意的要点:游标必须声明在declare中,使用open打开游标,fetch取游标中的数据,close关闭游标   隐式游标:主要是对DML数据的操作隐</div> </li> <li><a href="/article/1358.htm" title="JUnit4中@AfterClass @BeforeClass @after @before的区别对比" target="_blank">JUnit4中@AfterClass @BeforeClass @after @before的区别对比</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/JUnit4/1.htm">JUnit4</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/1.htm">单元测试</a> <div>一.基础知识 JUnit4使用Java5中的注解(annotation),以下是JUnit4常用的几个annotation: @Before:初始化方法   对于每一个测试方法都要执行一次(注意与BeforeClass区别,后者是对于所有方法执行一次)@After:释放资源  对于每一个测试方法都要执行一次(注意与AfterClass区别,后者是对于所有方法执行一次</div> </li> <li><a href="/article/1485.htm" title="精通Oracle10编程SQL(12)开发包" target="_blank">精通Oracle10编程SQL(12)开发包</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/plsql/1.htm">plsql</a> <div>/* *开发包 *包用于逻辑组合相关的PL/SQL类型(例如TABLE类型和RECORD类型)、PL/SQL项(例如游标和游标变量)和PL/SQL子程序(例如过程和函数) */ --包用于逻辑组合相关的PL/SQL类型、项和子程序,它由包规范和包体两部分组成 --建立包规范:包规范实际是包与应用程序之间的接口,它用于定义包的公用组件,包括常量、变量、游标、过程和函数等 --在包规</div> </li> <li><a href="/article/1612.htm" title="【EhCache二】ehcache.xml配置详解" target="_blank">【EhCache二】ehcache.xml配置详解</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/ehcache.xml/1.htm">ehcache.xml</a> <div>在ehcache官网上找了多次,终于找到ehcache.xml配置元素和属性的含义说明文档了,这个文档包含在ehcache.xml的注释中! ehcache.xml : http://ehcache.org/ehcache.xml ehcache.xsd : http://ehcache.org/ehcache.xsd ehcache配置文件的根元素是ehcahe   ehcac</div> </li> <li><a href="/article/1739.htm" title="java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderL" target="_blank">java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderL</a> <span class="text-muted">白糖_</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/eclipse/1.htm">eclipse</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/tomcat/1.htm">tomcat</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a> <div>今天学习spring+cxf的时候遇到一个问题:在web.xml中配置了spring的上下文监听器: <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>  随后启动</div> </li> <li><a href="/article/1866.htm" title="angular.element" target="_blank">angular.element</a> <span class="text-muted">boyitech</span> <a class="tag" taget="_blank" href="/search/AngularJS/1.htm">AngularJS</a><a class="tag" taget="_blank" href="/search/AngularJS+API/1.htm">AngularJS API</a><a class="tag" taget="_blank" href="/search/angular.element/1.htm">angular.element</a> <div>angular.element 描述:     包裹着一部分DOM element或者是HTML字符串,把它作为一个jQuery元素来处理。(类似于jQuery的选择器啦)     如果jQuery被引入了,则angular.element就可以看作是jQuery选择器,选择的对象可以使用jQuery的函数;如果jQuery不可用,angular.e</div> </li> <li><a href="/article/1993.htm" title="java-给定两个已排序序列,找出共同的元素。" target="_blank">java-给定两个已排序序列,找出共同的元素。</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div> import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class CommonItemInTwoSortedArray { /** * 题目:给定两个已排序序列,找出共同的元素。 * 1.定义两个指针分别指向序列的开始。 * 如果指向的两个元素</div> </li> <li><a href="/article/2120.htm" title="sftp 异常,有遇到的吗?求解" target="_blank">sftp 异常,有遇到的吗?求解</a> <span class="text-muted">Chen.H</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/jcraft/1.htm">jcraft</a><a class="tag" taget="_blank" href="/search/auth/1.htm">auth</a><a class="tag" taget="_blank" href="/search/jsch/1.htm">jsch</a><a class="tag" taget="_blank" href="/search/jschexception/1.htm">jschexception</a> <div>com.jcraft.jsch.JSchException: Auth cancel at com.jcraft.jsch.Session.connect(Session.java:460) at com.jcraft.jsch.Session.connect(Session.java:154) at cn.vivame.util.ftp.SftpServerAccess.connec</div> </li> <li><a href="/article/2247.htm" title="[生物智能与人工智能]神经元中的电化学结构代表什么?" target="_blank">[生物智能与人工智能]神经元中的电化学结构代表什么?</a> <span class="text-muted">comsci</span> <a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a> <div>     我这里做一个大胆的猜想,生物神经网络中的神经元中包含着一些化学和类似电路的结构,这些结构通常用来扮演类似我们在拓扑分析系统中的节点嵌入方程一样,使得我们的神经网络产生智能判断的能力,而这些嵌入到节点中的方程同时也扮演着"经验"的角色....      我们可以尝试一下...在某些神经</div> </li> <li><a href="/article/2374.htm" title="通过LAC和CID获取经纬度信息" target="_blank">通过LAC和CID获取经纬度信息</a> <span class="text-muted">dai_lm</span> <a class="tag" taget="_blank" href="/search/lac/1.htm">lac</a><a class="tag" taget="_blank" href="/search/cid/1.htm">cid</a> <div>方法1: 用浏览器打开http://www.minigps.net/cellsearch.html,然后输入lac和cid信息(mcc和mnc可以填0),如果数据正确就可以获得相应的经纬度 方法2: 发送HTTP请求到http://www.open-electronics.org/celltrack/cell.php?hex=0&lac=<lac>&cid=&</div> </li> <li><a href="/article/2501.htm" title="JAVA的困难分析" target="_blank">JAVA的困难分析</a> <span class="text-muted">datamachine</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>前段时间转了一篇SQL的文章(http://datamachine.iteye.com/blog/1971896),文章不复杂,但思想深刻,就顺便思考了一下java的不足,当砖头丢出来,希望引点和田玉。   -----------------------------------------------------------------------------------------</div> </li> <li><a href="/article/2628.htm" title="小学5年级英语单词背诵第二课" target="_blank">小学5年级英语单词背诵第二课</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/english/1.htm">english</a><a class="tag" taget="_blank" href="/search/word/1.htm">word</a> <div>money 钱 paper 纸 speak 讲,说 tell 告诉   remember 记得,想起 knock 敲,击,打 question 问题 number 数字,号码   learn 学会,学习 street 街道 carry 搬运,携带 send 发送,邮寄,发射   must 必须 light 灯,光线,轻的 front </div> </li> <li><a href="/article/2755.htm" title="linux下面没有tree命令" target="_blank">linux下面没有tree命令</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a> <div>centos p安装 yum -y install tree   mac os安装 brew install tree   首先来看tree的用法 tree 中文解释:tree 功能说明:以树状图列出目录的内容。 语  法:tree [-aACdDfFgilnNpqstux][-I <范本样式>][-P <范本样式</div> </li> <li><a href="/article/2882.htm" title="Map迭代方式,Map迭代,Map循环" target="_blank">Map迭代方式,Map迭代,Map循环</a> <span class="text-muted">蕃薯耀</span> <a class="tag" taget="_blank" href="/search/Map%E5%BE%AA%E7%8E%AF/1.htm">Map循环</a><a class="tag" taget="_blank" href="/search/Map%E8%BF%AD%E4%BB%A3/1.htm">Map迭代</a><a class="tag" taget="_blank" href="/search/Map%E8%BF%AD%E4%BB%A3%E6%96%B9%E5%BC%8F/1.htm">Map迭代方式</a> <div>Map迭代方式,Map迭代,Map循环   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 蕃薯耀 2015年</div> </li> <li><a href="/article/3009.htm" title="Spring Cache注解+Redis" target="_blank">Spring Cache注解+Redis</a> <span class="text-muted">hanqunfeng</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a> <div>Spring3.1 Cache注解  依赖jar包: <!-- redis --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> </div> </li> <li><a href="/article/3136.htm" title="Guava中针对集合的 filter和过滤功能" target="_blank">Guava中针对集合的 filter和过滤功能</a> <span class="text-muted">jackyrong</span> <a class="tag" taget="_blank" href="/search/filter/1.htm">filter</a> <div>在guava库中,自带了过滤器(filter)的功能,可以用来对collection 进行过滤,先看例子:    @Test public void whenFilterWithIterables_thenFiltered() { List<String> names = Lists.newArrayList("John"</div> </li> <li><a href="/article/3263.htm" title="学习编程那点事" target="_blank">学习编程那点事</a> <span class="text-muted">lampcy</span> <a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/html5/1.htm">html5</a> <div>一年前的夏天,我还在纠结要不要改行,要不要去学php?能学到真本事吗?改行能成功吗?太多的问题,我终于不顾一切,下定决心,辞去了工作,来到传说中的帝都。老师给的乘车方式还算有效,很顺利的就到了学校,赶巧了,正好学校搬到了新校区。先安顿了下来,过了个轻松的周末,第一次到帝都,逛逛吧! 接下来的周一,是我噩梦的开始,学习内容对我这个零基础的人来说,除了勉强完成老师布置的作业外,我已经没有时间和精力去</div> </li> <li><a href="/article/3390.htm" title="架构师之流处理---------bytebuffer的mark,limit和flip" target="_blank">架构师之流处理---------bytebuffer的mark,limit和flip</a> <span class="text-muted">nannan408</span> <a class="tag" taget="_blank" href="/search/ByteBuffer/1.htm">ByteBuffer</a> <div>1.前言。   如题,limit其实就是可以读取的字节长度的意思,flip是清空的意思,mark是标记的意思 。 2.例子. 例子代码: String str = "helloWorld"; ByteBuffer buff = ByteBuffer.wrap(str.getBytes()); Sy</div> </li> <li><a href="/article/3517.htm" title="org.apache.el.parser.ParseException: Encountered " ":" ": "" at line 1, column 1" target="_blank">org.apache.el.parser.ParseException: Encountered " ":" ": "" at line 1, column 1</a> <span class="text-muted">Everyday都不同</span> <a class="tag" taget="_blank" href="/search/%24/1.htm">$</a><a class="tag" taget="_blank" href="/search/%E8%BD%AC%E4%B9%89/1.htm">转义</a><a class="tag" taget="_blank" href="/search/el%E8%A1%A8%E8%BE%BE%E5%BC%8F/1.htm">el表达式</a> <div>最近在做Highcharts的过程中,在写js时,出现了以下异常:   严重: Servlet.service() for servlet jsp threw exception org.apache.el.parser.ParseException: Encountered " ":" ": "" at line 1, </div> </li> <li><a href="/article/3644.htm" title="用Java实现发送邮件到163" target="_blank">用Java实现发送邮件到163</a> <span class="text-muted">tntxia</span> <a class="tag" taget="_blank" href="/search/java%E5%AE%9E%E7%8E%B0/1.htm">java实现</a> <div>/* 在java版经常看到有人问如何用javamail发送邮件?如何接收邮件?如何访问多个文件夹等。问题零散,而历史的回复早已经淹没在问题的海洋之中。 本人之前所做过一个java项目,其中包含有WebMail功能,当初为用java实现而对javamail摸索了一段时间,总算有点收获。看到论坛中的经常有此方面的问题,因此把我的一些经验帖出来,希望对大家有些帮助。 此篇仅介绍用</div> </li> <li><a href="/article/3771.htm" title="探索实体类存在的真正意义" target="_blank">探索实体类存在的真正意义</a> <span class="text-muted">java小叶檀</span> <a class="tag" taget="_blank" href="/search/POJO/1.htm">POJO</a> <div>一. 实体类简述    实体类其实就是俗称的POJO,这种类一般不实现特殊框架下的接口,在程序中仅作为数据容器用来持久化存储数据用的 POJO(Plain Old Java Objects)简单的Java对象   它的一般格式就是 public class A{ private String id; public Str</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>