一、网络爬虫的定义
网络爬虫,即Web Spider,是一个很形象的名字。
把互联网比喻成一个蜘蛛网,那么Spider就是在网上爬来爬去的蜘蛛。 网络蜘蛛是通过网页的链接地址来寻找网页的。
从网站某一个页面(通常是首页)开始,读取网页的内容,找到在网页中的其它链接地址,
然后通过这些链接地址寻找下一个网页,这样一直循环下去,直到把这个网站所有的网页都抓取完为止。
如果把整个互联网当成一个网站,那么网络蜘蛛就可以用这个原理把互联网上所有的网页都抓取下来。
这样看来,网络爬虫就是一个爬行程序,一个抓取网页的程序。
网络爬虫的基本操作是抓取网页。
那么如何才能随心所欲地获得自己想要的页面?
我们先从URL开始。
二、浏览网页的过程
抓取网页的过程其实和读者平时使用IE浏览器浏览网页的道理是一样的。
比如说你在浏览器的地址栏中输入 www.baidu.com 这个地址。
打开网页的过程其实就是浏览器作为一个浏览的“客户端”,向服务器端发送了 一次请求,把服务器端的文件“抓”到本地,再进行解释、展现。
HTML是一种标记语言,用标签标记内容并加以解析和区分。
浏览器的功能是将获取到的HTML代码进行解析,然后将原始的代码转变成我们直接看到的网站页面。
三、URI的概念和举例
简单的来讲,URL就是在浏览器端输入的 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的格式由三部分组成:
①第一部分是协议(或称为服务方式)。
②第二部分是存有该资源的主机IP地址(有时也包括端口号)。
③第三部分是主机资源的具体地址,如目录和文件名等。
第一部分和第二部分用“://”符号隔开,
第二部分和第三部分用“/”符号隔开。
第一部分和第二部分是不可缺少的,第三部分有时可以省略。
下面来看看两个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抓取网页内容
分类: 爬虫 Python 2013-05-13 23:45 1628人阅读 收藏 举报
所谓网页抓取,就是把URL地址中指定的网络资源从网络流中读取出来,保存到本地。 类似于使用程序模拟IE浏览器的功能,把URL作为HTTP请求的内容发送到服务器端, 然后读取服务器端的响应资源。
在Python中,我们使用urllib2这个组件来抓取网页。 urllib2是Python的一个获取URLs(Uniform Resource Locators)的组件。
它以urlopen函数的形式提供了一个非常简单的接口。
最简单的urllib2的应用代码只需要四行。
我们新建一个文件urllib2_test01.py来感受一下urllib2的作用:
import urllib2
response = urllib2.urlopen('http://www.baidu.com/' )
html = response.read()
print html
按下F5可以看到运行的结果:
我们可以打开百度主页,右击,选择查看源代码(火狐OR谷歌浏览器均可),会发现也是完全一样的内容。
也就是说,上面这四行代码将我们访问百度时浏览器收到的代码们全部打印了出来。
这就是一个最简单的urllib2的例子。
除了"http:",URL同样可以使用"ftp:","file:"等等来替代。
HTTP是基于请求和应答机制的:
客户端提出请求,服务端提供应答。
urllib2用一个Request对象来映射你提出的HTTP请求。
在它最简单的使用形式中你将用你要请求的地址创建一个Request对象,
通过调用urlopen并传入Request对象,将返回一个相关请求response对象,
这个应答对象如同一个文件对象,所以你可以在Response中调用.read()。
我们新建一个文件urllib2_test02.py来感受一下:
import urllib2
req = urllib2.Request('http://www.baidu.com' )
response = urllib2.urlopen(req)
the_page = response.read()
print the_page
可以看到输出的内容和test01是一样的。
urllib2使用相同的接口处理所有的URL头。例如你可以像下面那样创建一个ftp请求。
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来感受一下:
import urllib
import urllib2
url = 'http://www.someserver.com/register.cgi'
values = {'name' : 'WHY' ,
'location' : 'SDU' ,
'language' : 'Python' }
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
the_page = response.read()
如果没有传送data参数,urllib2使用GET方式的请求。
GET和POST请求的不同之处是POST请求通常有"副作用",
它们会由于某种途径改变系统状态(例如提交成堆垃圾到你的门口)。
Data同样可以通过在Get请求的URL本身上面编码来传送。
import urllib2
import urllib
data = {}
data['name' ] = 'WHY'
data['location' ] = 'SDU'
data['language' ] = 'Python'
url_values = urllib.urlencode(data)
print url_values
name=Somebody+Here&language=Python&location=Northampton
url = 'http://www.example.com/example.cgi'
full_url = url + '?' + url_values
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。
import urllib
import urllib2
url = 'http://www.someserver.com/cgi-bin/register.cgi'
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
values = {'name' : 'WHY' ,
'location' : 'SDU' ,
'language' : 'Python' }
headers = { 'User-Agent' : user_agent }
data = urllib.urlencode(values)
req = urllib2.Request(url, data, headers)
response = urllib2.urlopen(req)
the_page = response.read()
[Python]网络爬虫(三):异常的处理和HTTP状态码的分类
分类: Python 爬虫 2013-05-14 09:51 1358人阅读 收藏 举报
先来说一说HTTP的异常处理问题。 当urlopen不能够处理一个response时,产生urlError。 不过通常的Python APIs异常如ValueError,TypeError等也会同时产生。 HTTPError是urlError的子类,通常在特定HTTP URLs中产生。 1.URLError 通常,URLError在没有网络连接(没有路由到特定服务器),或者服务器不存在的情况下产生。
这种情况下,异常同样会带有"reason"属性,它是一个tuple(可以理解为不可变的数组),
包含了一个错误号和一个错误信息。
我们建一个urllib2_test06.py来感受一下异常的处理:
import urllib2
req = urllib2.Request('http://www.baibai.com' )
try : urllib2.urlopen(req)
except urllib2.URLError, e:
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来感受一下:
import urllib2
req = urllib2.Request('http://bbs.csdn.net/callmewhy' )
try :
urllib2.urlopen(req)
except urllib2.URLError, e:
print e.code
按下F5可以看见输出了404的错误码,也就说没有找到这个页面。
3.Wrapping
所以如果你想为HTTPError或URLError做准备,将有两个基本的办法。推荐使用第二种。
我们建一个urllib2_test08.py来示范一下第一种异常处理的方案:
from urllib2 import Request, urlopen, URLError, HTTPError
req = Request('http://bbs.csdn.net/callmewhy' )
try :
response = urlopen(req)
except HTTPError, e:
print 'The server couldn\'t fulfill the request.'
print 'Error code: ' , e.code
except URLError, e:
print 'We failed to reach a server.'
print 'Reason: ' , e.reason
else :
print 'No exception was raised.'
和其他语言相似,try之后捕获异常并且将其内容打印出来。
这里要注意的一点,except HTTPError 必须在第一个,否则except URLError将同样接受到HTTPError 。 因为HTTPError是URLError的子类,如果URLError在前面它会捕捉到所有的URLError(包括HTTPError )。
我们建一个urllib2_test09.py来示范一下第二种异常处理的方案:
from urllib2 import Request, urlopen, URLError, HTTPError
req = Request('http://bbs.csdn.net/callmewhy' )
try :
response = urlopen(req)
except URLError, e:
if hasattr(e, 'reason' ):
print 'We failed to reach a server.'
print 'Reason: ' , e.reason
elif hasattr(e, 'code' ):
print 'The server couldn\'t fulfill the request.'
print 'Error code: ' , e.code
else :
print 'No exception was raised.'
[Python]网络爬虫(四):Opener与Handler的介绍和实例应用
分类: Python 爬虫 2013-05-14 15:09 1087人阅读 收藏 举报
在开始后面的内容之前,先来解释一下urllib2中的两个个方法: info and geturl
urlopen返回的应答对象response(或者HTTPError实例)有两个很有用的方法info()和geturl()
1.geturl():
这个返回获取的真实的URL,这个很有用,因为urlopen(或者opener对象使用的)或许 会有重定向。获取的URL或许跟请求URL不同。
以人人中的一个超级链接为例,
我们建一个urllib2_test10.py来比较一下原始URL和重定向的链接 :
from urllib2 import Request, urlopen, URLError, HTTPError
old_url = 'http://rrurl.cn/b1UZuP'
req = Request(old_url)
response = urlopen(req)
print 'Old url :' + old_url
print 'Real url :' + response.geturl()
运行之后可以看到真正的链接指向的网址:
2.info():
这个返回对象的字典对象,该字典描述了获取的页面情况。通常是服务器发送的特定头headers。目前是httplib.HTTPMessage 实例。
经典的headers包含"Content-length","Content-type",和其他内容。
我们建一个urllib2_test11.py来测试一下info的应用:
from urllib2 import Request, urlopen, URLError, HTTPError
old_url = 'http://www.baidu.com'
req = Request(old_url)
response = urlopen(req)
print 'Info():'
print response.info()
运行的结果如下,可以看到页面的相关信息:
下面来说一说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的应用:
import urllib2
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
top_level_url = "http://example.com/foo/"
password_mgr.add_password(None , top_level_url, 'why' , '1223' )
handler = urllib2.HTTPBasicAuthHandler(password_mgr)
opener = urllib2.build_opener(handler)
a_url = 'http://www.baidu.com/'
opener.open(a_url)
urllib2.install_opener(opener)
注意:以上的例子我们 仅仅提供我们的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]网络爬虫(四):Opener与Handler的介绍和实例应用
分类: Python 爬虫 2013-05-14 15:09 1087人阅读 收藏 举报
在开始后面的内容之前,先来解释一下urllib2中的两个个方法: info and geturl
urlopen返回的应答对象response(或者HTTPError实例)有两个很有用的方法info()和geturl()
1.geturl():
这个返回获取的真实的URL,这个很有用,因为urlopen(或者opener对象使用的)或许 会有重定向。获取的URL或许跟请求URL不同。
以人人中的一个超级链接为例,
我们建一个urllib2_test10.py来比较一下原始URL和重定向的链接 :
from urllib2 import Request, urlopen, URLError, HTTPError
old_url = 'http://rrurl.cn/b1UZuP'
req = Request(old_url)
response = urlopen(req)
print 'Old url :' + old_url
print 'Real url :' + response.geturl()
运行之后可以看到真正的链接指向的网址:
2.info():
这个返回对象的字典对象,该字典描述了获取的页面情况。通常是服务器发送的特定头headers。目前是httplib.HTTPMessage 实例。
经典的headers包含"Content-length","Content-type",和其他内容。
我们建一个urllib2_test11.py来测试一下info的应用:
from urllib2 import Request, urlopen, URLError, HTTPError
old_url = 'http://www.baidu.com'
req = Request(old_url)
response = urlopen(req)
print 'Info():'
print response.info()
运行的结果如下,可以看到页面的相关信息:
下面来说一说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的应用:
import urllib2
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
top_level_url = "http://example.com/foo/"
password_mgr.add_password(None , top_level_url, 'why' , '1223' )
handler = urllib2.HTTPBasicAuthHandler(password_mgr)
opener = urllib2.build_opener(handler)
a_url = 'http://www.baidu.com/'
opener.open(a_url)
urllib2.install_opener(opener)
注意:以上的例子我们 仅仅提供我们的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的使用细节与抓站技巧
分类: 爬虫 Python 2013-05-14 16:21 1250人阅读 收藏 举报
前面说到了urllib2的简单入门,下面整理了一部分urllib2的使用细节。
1.Proxy 的设置
urllib2 默认会使用环境变量 http_proxy 来设置 HTTP Proxy。
如果想在程序中明确控制 Proxy 而不受环境变量的影响,可以使用代理。
新建test14来实现一个简单的代理Demo:
import urllib2
enable_proxy = True
proxy_handler = urllib2.ProxyHandler({"http" : 'http://some-proxy.com:8080' })
null_proxy_handler = urllib2.ProxyHandler({})
if enable_proxy:
opener = urllib2.build_opener(proxy_handler)
else :
opener = urllib2.build_opener(null_proxy_handler)
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 值。
import urllib2
import socket
socket.setdefaulttimeout(10 )
urllib2.socket.setdefaulttimeout(10 )
在 Python 2.6 以后,超时可以通过 urllib2.urlopen() 的 timeout 参数直接设置。
import urllib2
response = urllib2.urlopen('http://www.google.com' , timeout= 10 )
3.在 HTTP Request 中加入特定的 Header
要加入 header,需要使用 Request 对象:
import urllib2
request = urllib2.Request('http://www.baidu.com/' )
request.add_header('User-Agent' , 'fake-client' )
response = urllib2.urlopen(request)
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 是否一致就可以了。
import urllib2
my_url = 'http://www.google.cn'
response = urllib2.urlopen(my_url)
redirected = response.geturl() == my_url
print redirected
my_url = 'http://rrurl.cn/b1UZuP'
response = urllib2.urlopen(my_url)
redirected = response.geturl() == my_url
print redirected
如果不想自动 redirect,除了使用更低层次的 httplib 库之外,还可以自定义HTTPRedirectHandler 类。
import urllib2
class RedirectHandler(urllib2.HTTPRedirectHandler):
def http_error_301( self , req, fp, code, msg, headers):
print "301"
pass
def http_error_302( self , req, fp, code, msg, headers):
print "303"
pass
opener = urllib2.build_opener(RedirectHandler)
opener.open('http://rrurl.cn/b1UZuP' )
5.Cookie
urllib2 对 Cookie 的处理也是自动的。如果需要得到某个 Cookie 项的值,可以这么做:
import urllib2
import cookielib
cookie = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
response = opener.open('http://www.baidu.com' )
for item in cookie:
print 'Name = ' +item.name
print 'Value = ' +item.value
运行之后就会输出访问百度的Cookie值:
6.使用 HTTP 的 PUT 和 DELETE 方法
urllib2 只支持 HTTP 的 GET 和 POST 方法,如果要使用 HTTP PUT 和 DELETE ,只能使用比较低层的 httplib 库。虽然如此,我们还是能通过下面的方式,使 urllib2 能够发出 PUT 或DELETE 的请求:
import urllib2
request = urllib2.Request(uri, data=data)
request.get_method = lambda : 'PUT'
response = urllib2.urlopen(request)
7.得到 HTTP 的返回码
对于 200 OK 来说,只要使用 urlopen 返回的 response 对象的 getcode() 方法就可以得到 HTTP 的返回码。但对其它返回码来说,urlopen 会抛出异常。这时候,就要检查异常对象的 code 属性了:
import urllib2
try :
response = urllib2.urlopen('http://bbs.csdn.net/why' )
except urllib2.HTTPError, e:
print e.code
8. Debug Log
使用 urllib2 时,可以通过下面的方法把 debug Log 打开,这样收发包的内容就会在屏幕上打印出来,方便调试,有时可以省去抓包的工作
import urllib2
httpHandler = urllib2.HTTPHandler(debuglevel=1 )
httpsHandler = urllib2.HTTPSHandler(debuglevel=1 )
opener = urllib2.build_opener(httpHandler, httpsHandler)
urllib2.install_opener(opener)
response = urllib2.urlopen('http://www.google.com' )
这样就可以看到传输的数据包内容了:
9.表单的处理
登录必要填表,表单怎么填?
首先利用工具截取所要填表的内容。 比如我一般用firefox+httpfox插件来看看自己到底发送了些什么包。 以verycd为例,先找到自己发的POST请求,以及POST表单项。 可以看到verycd的话需要填username,password,continueURI,fk,login_submit这几项,其中fk是随机生成的(其实不太随机,看上去像是把epoch时间经过简单的编码生成的),需要从网页获取,也就是说得先访问一次网页,用正则表达式等工具截取返回数据中的fk项。continueURI顾名思义可以随便写,login_submit是固定的,这从源码可以看出。还有username,password那就很显然了:
import urllib
import urllib2
postdata=urllib.urlencode({
'username' : '汪小光' ,
'password' : 'why888' ,
'continueURI' : 'http://www.verycd.com/' ,
'fk' : '' ,
'login_submit' : '登录'
})
req = urllib2.Request(
url = 'http://secure.verycd.com/signin' ,
data = postdata
)
result = urllib2.urlopen(req)
print result.read()
10.伪装成浏览器访问 某些网站反感爬虫的到访,于是对爬虫一律拒绝请求 这时候我们需要伪装成浏览器,这可以通过修改http包中的header来实现
headers = {
'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'
}
req = urllib2.Request(
url = 'http://secure.verycd.com/signin/*/http://www.verycd.com/' ,
data = postdata,
headers = headers
)
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 2013-05-14 21:36 1185人阅读 收藏 举报
import string, urllib2
def baidu_tieba(url,begin_page,end_page):
for i in range(begin_page, end_page+ 1 ):
sName = string.zfill(i,5 ) + '.html'
print '正在下载第' + str(i) + '个网页,并将其存储为' + sName + '......'
f = open(sName,'w+' )
m = urllib2.urlopen(url + str(i)).read()
f.write(m)
f.close()
bdurl = str(raw_input(u'请输入贴吧的地址,去掉pn=后面的数字:\n' ))
begin_page = int(raw_input(u'请输入开始的页数:\n' ))
end_page = int(raw_input(u'请输入终点的页数:\n' ))
baidu_tieba(bdurl,begin_page,end_page)
[Python]网络爬虫(七):Python中的正则表达式教程
分类: 爬虫 Python 2013-05-15 13:29 1212人阅读 收藏 举报
接下来准备用糗百做一个爬虫的小例子。
但是在这之前,先详细的整理一下Python中的正则表达式的相关内容。
正则表达式在Python爬虫中的作用就像是老师点名时用的花名册一样,是必不可少的神兵利器。
一、 正则表达式基础
1.1.概念介绍
正则表达式是用于处理字符串的强大工具,它并不是Python的一部分。
其他编程语言中也有正则表达式的概念,区别只在于不同的编程语言实现支持的语法数量不同。
它拥有自己独特的语法以及一个独立的处理引擎,在提供了正则表达式的语言里,正则表达式的语法都是一样的。
下图展示了使用正则表达式进行匹配的流程:
正则表达式的大致匹配过程是:
1.依次拿出表达式和文本中的字符比较,
2.如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。
3.如果表达式中有量词或边界,这个过程会稍微有一些不同。 下图列出了Python支持的正则表达式元字符和语法:
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的应用:
import re
pattern = re.compile(r'hello' )
match1 = pattern.match('hello world!' )
match2 = pattern.match('helloo world!' )
match3 = pattern.match('helllo world!' )
if match1:
print match1.group()
else :
print 'match1匹配失败!'
if match2:
print match2.group()
else :
print 'match2匹配失败!'
if match3:
print match3.group()
else :
print 'match3匹配失败!'
可以看到控制台输出了匹配的三个结果:
下面来具体看看代码中的关键方法。
★ 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): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。
以下两个正则表达式是等价的:
import re
a = re.compile(r
, re.X)
b = re.compile(r"\d+\.\d*" )
match11 = a.match('3.1415' )
match12 = a.match('33' )
match21 = b.match('3.1415' )
match22 = b.match('33' )
if match11:
print match11.group()
else :
print u 'match11不是小数'
if match12:
print match12.group()
else :
print u 'match12不是小数'
if match21:
print match21.group()
else :
print u 'match21不是小数'
if match22:
print match22.group()
else :
print u 'match22不是小数'
re提供了众多模块方法用于完成正则表达式的功能。
这些方法可以使用Pattern实例的相应方法替代,唯一的好处是少写一行re.compile()代码,
但同时也无法复用编译后的Pattern对象。
这些方法将在Pattern类的实例方法部分一起介绍。
如一开始的hello实例可以简写为:
# -*- coding: utf-8 -*-
#一个简单的re实例,匹配字符串中的hello字符串
import re
m = re .match(r'hello', 'hello world!')
print m.group()
re模块还提供了一个方法escape(string),用于将string中的正则表达式元字符如*/+/?等之前加上转义符再返回
2.2. Match
Match对象是一次匹配的结果,包含了很多关于此次匹配的信息,可以使用Match提供的可读属性或方法来获取这些信息。
属性:
string: 匹配时使用的文本。
re: 匹配时使用的Pattern对象。
pos: 文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
endpos: 文本中正则表达式结束搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
lastindex: 最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None。
lastgroup: 最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将为None。
方法:
group([group1, …]): 获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名;编号0代表整个匹配的子串;不填写参数时,返回group(0);没有截获字符串的组返回None;截获了多次的组返回最后一次截获的子串。
groups([default]): 以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。default表示没有截获字符串的组以这个值替代,默认为None。
groupdict([default]): 返回以有别名的组的别名为键、以该组截获的子串为值的字典,没有别名的组不包含在内。default含义同上。
start([group]): 返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。group默认值为0。
end([group]): 返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1)。group默认值为0。
span([group]): 返回(start(group), end(group))。
expand(template): 将匹配到的分组代入template中然后返回。template中可以使用\id或\g、\g引用分组,但不能使用编号0。\id与\g是等价的;但\10将被认为是第10个分组,如果你想表达\1之后是字符'0',只能使用\g<1>0。
下面来用一个py实例输出所有的内容加深理解:
import re
m = re.match(r'(\w+) (\w+)(?P.*)' , 'hello world!' )
print "m.string:" , m.string
print "m.re:" , m.re
print "m.pos:" , m.pos
print "m.endpos:" , m.endpos
print "m.lastindex:" , m.lastindex
print "m.lastgroup:" , m.lastgroup
print "m.group():" , m.group()
print "m.group(1,2):" , m.group( 1 , 2 )
print "m.groups():" , m.groups()
print "m.groupdict():" , m.groupdict()
print "m.start(2):" , m.start( 2 )
print "m.end(2):" , m.end( 2 )
print "m.span(2):" , m.span( 2 )
print r "m.expand(r'\g<2> \g<1>\g<3>'):" , m.expand(r '\2 \1\3' )
2.3. Pattern
Pattern对象是一个编译好的正则表达式,通过Pattern提供的一系列方法可以对文本进行匹配查找。
Pattern不能直接实例化,必须使用re.compile()进行构造,也就是re.compile()返回的对象。
Pattern提供了几个可读属性用于获取表达式的相关信息:
pattern: 编译时用的表达式字符串。
flags: 编译时用的匹配模式。数字形式。
groups: 表达式中分组的数量。
groupindex: 以表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。
可以用下面这个例子查看pattern的属性:
import re
p = re.compile(r'(\w+) (\w+)(?P.*)' , re.DOTALL)
print "p.pattern:" , p.pattern
print "p.flags:" , p.flags
print "p.groups:" , p.groups
print "p.groupindex:" , p.groupindex
下面重点介绍一下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的简单案例:
import re
pattern = re.compile(r'hello' )
match = pattern.match('hello world!' )
if match:
print match.group()
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的实例:
import re
pattern = re.compile(r'world' )
match = pattern.search('hello world!' )
if match:
print match.group()
3.split
split(string[, maxsplit]) | re.split(pattern, string[, maxsplit]): 按照能够匹配的子串将string分割后返回列表。
maxsplit用于指定最大分割次数,不指定将全部分割。
import re
p = re.compile(r'\d+' )
print p.split( 'one1two2three3four4' )
4.findall
findall(string[, pos[, endpos]]) | re.findall(pattern, string[, flags]): 搜索string,以列表形式返回全部能匹配的子串。
import re
p = re.compile(r'\d+' )
print p.findall( 'one1two2three3four4' )
5.finditer
finditer(string[, pos[, endpos]]) | re.finditer(pattern, string[, flags]): 搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。
import re
p = re .compile(r'\d+')
for m in p.finditer('one1two2three3four4'):
print m.group(),
### output ###
# 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用于指定最多替换次数,不指定时全部替换。
import re
p = re.compile(r'(\w+) (\w+)' )
s = 'i say, hello world!'
print p.sub(r '\2 \1' , s)
def func(m):
return m.group( 1 ).title() + ' ' + m.group( 2 ).title()
print p.sub(func, s)
7.subn
subn(repl, string[, count]) |re.sub(pattern, repl, string[, count]): 返回 (sub(repl, string[, count]), 替换次数)。
import re
p = re.compile(r'(\w+) (\w+)' )
s = 'i say, hello world!'
print p.subn(r '\2 \1' , s)
def func(m):
return m.group( 1 ).title() + ' ' + m.group( 2 ).title()
print p.subn(func, s)
至此,Python的正则表达式基本介绍就算是完成了^_^
[Python]网络爬虫(八):糗事百科的网络爬虫(v0.2)源码及解析
分类: Python 爬虫 2013-05-15 20:59 1208人阅读 收藏 举报
项目内容:
用Python写的糗事百科的网络爬虫。
使用方法:
新建一个Bug.py文件,然后将代码复制到里面后,双击运行。
程序功能:
在命令提示行中浏览糗事百科。
原理解释:
首先,先浏览一下糗事百科的主页:http://www.qiushibaike.com/hot/page/1
可以看出来,链接中page/后面的数字就是对应的页码,记住这一点为以后的编写做准备。
然后,右击查看页面源码:
观察发现,每一个段子都用div标记,其中class必为content,title是发帖时间,我们只需要用正则表达式将其“扣”出来就可以了。
明白了原理之后,剩下的就是正则表达式的内容了,可以参照这篇博文:
http://blog.csdn.net/wxg694175346/article/details/8929576
运行效果:
import urllib2
import urllib
import re
import thread
import time
class HTML_Tool:
BgnCharToNoneRex = re.compile("(\t|\n| ||)" )
EndCharToNoneRex = re.compile("<.*?>" )
BgnPartRex = re.compile("" )
CharToNewLineRex = re.compile("( ||||
)")
CharToNextTabRex = re.compile(" ")
replaceTab = [("<" , "<" ),( ">" , ">" ),( "&" , "&" ),( "&" , "\"" ),( " " , " " )]
def Replace_Char( self ,x):
x = self .BgnCharToNoneRex.sub("",x)
x = self .BgnPartRex.sub( "\n " ,x)
x = self .CharToNewLineRex.sub( "\n" ,x)
x = self .CharToNextTabRex.sub( "\t" ,x)
x = self .EndCharToNoneRex.sub("",x)
for t in self .replaceTab:
x = x.replace(t[0 ],t[ 1 ])
return x
class HTML_Model:
def __init__( self ):
self .page = 1
self .pages = []
self .myTool = HTML_Tool()
self .enable = False
def GetPage( self ,page):
myUrl = "http://m.qiushibaike.com/hot/page/" + page
myResponse = urllib2.urlopen(myUrl)
myPage = myResponse.read()
unicodePage = myPage.decode("utf-8" )
myItems = re.findall('(.*?)' ,unicodePage,re.S)
items = []
for item in myItems:
items.append([item[0 ].replace( "\n" ," "),item[1].replace(" \n "," ")])
return items
def LoadPage( self ):
while self .enable:
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 ,q,page):
for items in q:
print u '第%d页' % page , items[ 0 ]
print self .myTool.Replace_Char(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:
if self .pages:
nowPage = self .pages[ 0 ]
del self .pages[ 0 ]
self .ShowPage(nowPage,page)
page += 1
print u
print u '请按下回车浏览今日的糗百内容:'
raw_input(' ' )
myModel = HTML_Model()
myModel.Start()
[Python]网络爬虫(九):百度贴吧的网络爬虫(v0.4)源码及解析
分类: 爬虫 Python 2013-05-16 13:48 1361人阅读 收藏 举报
百度贴吧的爬虫制作和糗百的爬虫制作原理基本相同,都是通过查看源码扣出关键数据,然后将其存储到本地txt文件。
项目内容:
用Python写的百度贴吧的网络爬虫。
使用方法:
新建一个BugBaidu.py文件,然后将代码复制到里面后,双击运行。
程序功能:
将贴吧中楼主发布的内容打包txt存储到本地。
原理解释:
首先,先浏览一下某一条贴吧,点击只看楼主并点击第二页之后url发生了一点变化,变成了:
http://tieba.baidu.com/p/2296712428?see_lz=1&pn=1
可以看出来,see_lz=1是只看楼主,pn=1是对应的页码,记住这一点为以后的编写做准备。
这就是我们需要利用的url。
接下来就是查看页面源码。
首先把题目抠出来存储文件的时候会用到。
可以看到百度使用gbk编码,标题使用h1标记:
< h1 class = "core_title_txt" title = "【原创】时尚首席(关于时尚,名利,事业,爱情,励志)" > 【原创】时尚首席(关于时尚,名利,事业,爱情,励志) h1 >
同样,正文部分用div和class综合标记,接下来要做的只是用正则表达式来匹配即可。
运行截图:
生成的txt文件:
import string
import urllib2
import re
class HTML_Tool:
BgnCharToNoneRex = re.compile("(\t|\n| ||)" )
EndCharToNoneRex = re.compile("<.*?>" )
BgnPartRex = re.compile("" )
CharToNewLineRex = re.compile("( ||||
)")
CharToNextTabRex = re.compile(" ")
replaceTab = [("<" , "<" ),( ">" , ">" ),( "&" , "&" ),( "&" , "\"" ),( " " , " " )]
def Replace_Char( self ,x):
x = self .BgnCharToNoneRex.sub("",x)
x = self .BgnPartRex.sub( "\n " ,x)
x = self .CharToNewLineRex.sub( "\n" ,x)
x = self .CharToNextTabRex.sub( "\t" ,x)
x = self .EndCharToNoneRex.sub("",x)
for t in self .replaceTab:
x = x.replace(t[0 ],t[ 1 ])
return x
class Baidu_Spider:
def __init__( self ,url):
self .myUrl = url + '?see_lz=1'
self .datas = []
self .myTool = HTML_Tool()
print u '已经启动百度贴吧爬虫,咔嚓咔嚓'
def baidu_tieba( self ):
myPage = urllib2.urlopen(self .myUrl).read().decode( "gbk" )
endPage = self .page_counter(myPage)
title = self .find_title(myPage)
print u '文章名称:' + title
self .save_data( self .myUrl,title,endPage)
def page_counter( self ,myPage):
myMatch = re.search(r'class="red">(\d+?) ' , myPage, re.S)
if myMatch:
endPage = int(myMatch.group(1 ))
print u '爬虫报告:发现楼主共有%d页的原创内容' % endPage
else :
endPage = 0
print u '爬虫报告:无法计算楼主发布内容有多少页!'
return endPage
def find_title( self ,myPage):
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()
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
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相关)
python to_excel 生成多个sheet页
Excel自学成才
python excel 开发语言
python相关学习资料:https://edu.51cto.com/video/4102.htmlhttps://edu.51cto.com/video/3502.htmlhttps://edu.51cto.com/video/1158.htmlPythontoExcel生成多个Sheet页作为一名经验丰富的开发者,我很高兴能帮助你学习如何使用Python生成Excel文件并包含多个Sheet页
《Python 面试热门问题五》
陈在天box
python 开发语言
一、引言Python作为一种广泛应用的高级编程语言,在各个领域都有着重要的地位。在面试中,Python相关的问题常常涉及到语言的基础知识、编程技巧、常用库的使用以及实际项目经验等方面。本文将围绕五个热门的Python面试问题进行深入探讨,帮助读者更好地准备Python面试,提升自己的编程能力和竞争力。二、问题一:Python的数据类型有哪些?(一)基本数据类型数字类型整数(int):Python中
python 提取filename的后缀
不是美少女
python 开发语言
Python相关视频讲解:python的or运算赋值用法用python编程Excel有没有用处?011_编程到底好玩在哪?查看python文件_输出py文件_cat_运行python文件_shel如何实现Python提取文件名的后缀作为一名经验丰富的开发者,我将会教你如何在Python中提取文件名的后缀。首先,让我们来整理一下实现这一功能的整个流程。开始获取文件名提取后缀结束获取文件名首先,我们需
Python相关系数导图
亚图跨际
交叉知识 Python 神经网络 量化特征关联 汽车性价比矩阵热图 流行病和资产价格 城镇化交通量 非线性捕捉 量化图像相似性 神经模型
要点量化变量和特征关联绘图对比皮尔逊相关系数、斯皮尔曼氏秩和肯德尔秩汽车性价比相关性矩阵热图大流行病与资产波动城镇化模型预测交通量宝可梦类别特征非线性依赖性捕捉向量加权皮尔逊相关系数量化图像相似性Python皮尔逊-斯皮尔曼-肯德尔皮尔逊相关系数在统计学中,皮尔逊相关系数是一种用于测量两组数据之间线性相关性的相关系数。它是两个变量的协方差与其标准差乘积的比率;因此,它本质上是协方差的标准化测量,其
mac 查看是否安装 python
掘金翻译计划
python macos 开发语言
python相关学习资料:https://edu.51cto.com/video/4645.htmlhttps://edu.51cto.com/video/4102.htmlhttps://edu.51cto.com/video/3502.html如何在Mac上检查是否安装了PythonPython是一种广泛使用的高级编程语言,它具有易于学习和使用的特点。在Mac操作系统中,Python通常作为预
通过VSCode开发Python项目
无忧无虑Coding
vscode python ide
一、插件准备Python插件,必须autoDocstring生成注释,和Pycharm一样输入三个引号"""会生产注释结构TodoTree高亮显示TODO/FIXME二、python相关设置一)设置python环境按"F1"打开命令面板(如果这个"F1"被占用,点击vscode左下角的齿轮,选择"CommandPalette…")选择"Python:SelectInterpreter"(可输入"P
python爬取网页内容大作业_【大数据应用技术】作业八|爬虫综合大作业(下)...
weixin_39720662
python爬取网页内容大作业
前言本次作业是爬取拉勾网python相关岗位的信息,通过爬取岗位id、城市、公司全名、福利待遇、工作地点、学历要求、工作类型、发布时间、职位名称、薪资、工作年限等数据并对其进行数据分析从而得出相应结论。网页爬虫1.代理IP在爬取数据之前我们可以考虑使用代理ip进行爬取,所以这里我写了一段代码检测ip的有效性,这里我使用的是西刺免费代理ip进行测试。不过在测试中我发现可用的免费代理ip少之又少,并且
Python一览
山水泽
近期正在复习之前学过的python相关知识,借此机会将所了解到的python相关内容整理成一系列文章,方便自己后续回顾以及其他需要的人。该系列文章的路径将从python语言基础开始,结合一些实际上的使用例子,有普遍到特殊,由简单到复杂的这样的一个路径来完成。该系列文章都是基于python3.x。之后本文会更新Python一览系列的文章列表链接
[2024]常用的conda指令
肆十二
小工具 conda
[2024]常用的conda指令Hi,各位新年好,今天给大家介绍一下Python项目开发中常用的工具-Anaconda。Anaconda指的是一个开源的Python发行版本,也是一个安装、管理Python相关包的软件。它自带了Python、JupyterNotebook、Spyder等工具,并且有管理包的conda工具,非常实用。Anaconda包含了conda、Python等180多个科学包及其
爬取猫眼电影 通过Python异步进行MongoDB存储
Serven_Students
讲解:使用Python中PyQuery库爬去猫眼电影并存入MongoDB数据库、txt文档、涉及到Python异步涉及Python相关库:fromurllib.robotparserimportRobotFileParserimportrequestsfrompyqueryimportPyQueryimportpymongoimportcopyimportasyncio下面展示一段神奇的代码:fr
手把手教你使用 VS Code 运行和调试 Python 程序
阿基米东
生产力工具 VS Code 开发利器 python vscode
本文以Ubuntu系统为例,介绍如何在VSCode上配置Python的编程环境,并把Python程序运行、调试起来。由于Python是解释型语言,并且VSCode中提供了内置的调试器可用于调试Python代码,因此配置和操作流程比调试C/C++代码要简单一些。准备工作安装Python解释器如果你的本地环境还没有Python,需要先安装Python相关开发工具,可以参考Python安装指南安装或升级
Python速成篇(基础语法)上
暴力的bug制造机
python 开发语言
引言都是我手欠非要报什么python的计算机二级,现在好了假期不但要冲C艹,还要学个python,用了几天的时间速成了一下python的基础语法,其实在学会C的基础上,py学起来是非常的快啊。这篇博客呢,建议有一定语言基础的朋友来看。没有接触过编程的朋友可以先看看python相关书籍或视频从0到1学,这里我推荐蟒蛇的python,浅显易懂。那么就开始接下来的正文内容吧。Python环境配置想要进行
Python相关的基础模块
Lyx-0607
笔记
Python相关的基础模块在编写远程控制工具之前,先要介绍用Python编写远程控制工具时所需要的相关模块,为接下来编写工具打下基础。1.subprocess模块subprocess模块的主要作用是执行外部的命令和程序。当我们运行Python的时候,其实也是在运行一个进程,而用subprocess模块可以创建一个子进程来执行命令。subprocess模块包含许多创建子进程的函数,这些函数分别以不同
在虚拟环境中导出和安装requirements.txt文件
acmakb
Python基础 实用技巧及常见bug python linux pip
背景:一般在项目开放完成后,我们需要把项目工程所需要的虚拟环境依赖包导出,以便在服务器上进行安装和配置,这时候我们一般将所需要的python相关库导出一个txt文件,后续在服务器上之前pip安装即可。措施:方案一:在相应的环境终端输入:pipfreeze>requirements.txt注意不是:freezen(web)E:\web\online_project>pipfreezen>requir
解决问题:python PermissionError: [WinError 5]拒绝访问
NI'CE'XIAN
python java 前端
重要:关闭PyCharmCommunityEdition2022.3等与python相关的编程程序找到按照python解释器的位置python->右键>属性>安全->点击'组或用户名"中的Users->编辑点击"组或用户名"中的Users->把"完全控制"打钩->应用->OK如果该文章帮助到了您,希望可以点赞支持一下作者。(●'◡'●)ノ
ArcGISPro中Python相关命令总结
Z_W_H_
ArcPy ArcPy
主要总结conda方面的相关命令列出当前活动环境中的包condalist列出所有conda环境condaenvlist克隆环境克隆以默认的arcgispro-py3环境为模版的my_env新环境。condacreate--clonearcgispro-py3--namemy_env--pinned激活环境activatemy_envproenv两者不同之处在于activate是激活指定环境,pro
Python相关题-编码规范
InsaneLoafer
编码规范7.什么是PEP8?答:PEP8通常会听别人提到,但是具体的指什么内容呢,简单介绍下。《PythonEnhancementProposal#8》(8号Python增强提案)又叫PEP8,他针对的Python代码格式而编订的风格指南。8.了解Python之禅么?答:通过importthis语句可以获取其具体的内容。它告诉大家如何写出高效整洁的代码。9.了解DocStrings么?答:DocS
OpenStack之通用组件介绍
慕慕她爸
python相关现在的OpenStack还是基于python2.7版本开发的(Juno版本已经不支持python2.6)OpenStackLiberty版本才开始支持python3检查操作系统默认python版本的命令:python-vpip是一个安装和管理python包的工具4.1配置国内pip镜像源方法:vi~/.pip/pip.conf[global]index-url=http://pyp
同是大专,为什么别人总比你优秀?
aaz913648653
下面这个是我的好朋友东哥的真实经历,希望能把他转行的经历分享出来,给正在转行路上努力的朋友们一个参考,转行路上以此共勉,也希望大家能多多关注他!接下来是他第一人称的自述:大专学历,转行成为Python开发者的故事我毕业六年了,但与技术和Python相关的工作经验也就两年。今天我想跟大家分享自己转行的故事,希望能够鼓励那些跟我一样的朋友共同前行。我们将会聊到我个人的经历和入行故事,个人的技术成就,我
大专学历,转行两年的 Python 开发者故事
csdn大数据
我毕业六年了,但与技术和Python相关的工作经验也就两年。今天我想跟大家分享自己转行的故事,希望能够鼓励那些跟我一样的朋友共同前行。我们将会聊到我个人的经历和入行故事,个人的技术成就,我2019年上半年和下半年的工作重点,讨论快速学习的方法,最后推荐一些学习资源。01个人简介和经历我叫韦世东,是一名Python开发者,同时也正在学习Rust语言。我并没有大厂履历,也没有太多的IT工作经历。我喜欢
VSCode中Python环境配置、虚拟环境的创建启动关闭及pip常用命令
艺晨星
vscode python pip
文章目录工具准备虚拟环境pip常用命令ipykernel库安装Python迁移项目时有第三方库的做法:pip安装升级相关命令用pip下载指定版本的包:Python相关包的介绍1.numpy参考资料:工具准备安装VisualStudioCode安装PythonVScode中安装插件:Python、Jupyter虚拟环境为了不影响原始安装包,一般新建虚拟环境编写Python代码。新建一个空的文件夹并用
代码随想录算法训练营day10 | 232.用栈实现队列、225. 用队列实现栈
sunflowers11
代码随想录 算法
python相关的栈与队列了解list的一些方法https://www.geeksforgeeks.org/list-methods-python/双端队列dequehttps://www.geeksforgeeks.org/deque-in-python/和C++不同,Python没有实现栈和队列特定的类,可以是使用list和deque实现https://www.geeksforgeeks.or
VScode下创建python虚拟环境
发疯的小猿
vscode 编辑器 笔记 python
1.安装了VSCode:确保你已经安装了VisualStudioCode。你可以从VSCode官方网站免费下载并安装。2.安装了python:确保你的计算机上安装了Python。你可以从Python官方网站下载并安装。3.安装Python插件:打开VSCode,在扩展(Extensions)市场中搜索并安装Python插件。此插件为VSCode提供了与Python相关的功能。4.创建项目文件夹:在
Python语言基础
Lyx-0607
python 笔记
“工欲善其事,必先利其器”,在开始进行期待已久的编程之前,首先需要搭建好开发环境。熟悉开发环境是学习一门语言的第一步,只有这样才能高效地实现程序的相应功能。本章将简单介绍Python相关基础知识,拥有良好的知识基础,将有利于后期的深入学习与研究。本章主要内容包括:·Python环境的搭建。·编写第一个Python程序。·Python模块的安装与使用。·Python语言的序列、控制结构、文件处理、异
python小游戏代码简单10行,python小游戏代码简单CSDN
小狗AI
pygame python
这篇文章主要介绍了python小游戏代码简单源代码无需导入图片的,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。Sourcecodedownload:本文相关源码嗨害大家好鸭,我是小熊猫很多小伙伴后台私信问我说,“python可以做游戏吗?”“要怎么做呢?”接下来我就介绍一下,如何用Python做游戏有什么python相关报错解答自己不会
构建高效的接口自动化测试框架思路
测试界的路飞
技术分享 软件测试 测试用例
在选择接口测试自动化框架时,需要根据团队的技术栈和项目需求来综合考虑。对于测试团队来说,使用Python相关的测试框架更为便捷。无论选择哪种框架,重要的是确保框架功能完备,易于维护和扩展,提高测试效率和准确性。今天小编介绍一个基于Python的接口自动化测试框架,结合了Python的Unittest框架、Requests库以及数据驱动思想,帮助您更好地实现接口测试。1.接口自动化测试项目框架简介搭
总结了90条简单实用的Python编程技巧
乔代码嘚
python 开发语言
编码原则**建议1:**理解Pythonic概念—-详见Python中的《Python之禅》**建议2:**编写Pythonic代码(1)避免不规范代码,比如只用大小写区分变量、使用容易混淆的变量名、害怕过长变量名等。有时候长的变量名会使代码更加具有可读性。(2)深入学习Python相关知识,比如语言特性、库特性等,比如Python演变过程等。深入学习一两个业内公认的Pythonic的代码库,比如
npm下载依赖报Python,c++等相关错误
即将头秃的程序媛
npm 前端 node.js
执行npminstall下载时,报错,缺少python相关的错解决方法://下载python1、npminstall--global--productionwindows-build-tools//配置环境:也可暂时不用配置,能用就不用配置(npmconfigsetpython"D:\Python27\python.exe"npmconfigsetnode_gyp)2、//下载fibersnpmi
全国计算机等级考试二级python相关知识点
Zosea231
学习笔记 python 网络 开发语言
PYTHON-计算机二级本文章整理了全国计算机等级考试二级python的相关知识点,还在学习中,疏漏之处请予斧正!2023/9/25考完更新,time库没有考到,序列类型的操作考察较多!本文章参考视频:2021年考必看!全国计算机二级Python考试科目,全网最新的计算机真题知识点数据类型、文件操作基础数据类型Python中的整数是动态长度的,可以根据需要增加其精度,以容纳较大的整数值。组合数据类
ERROR: Could not install packages due to an OSError: [WinError 5] 拒绝访问。: ‘e:\\python\\python-envs1\\
浅墨\
python环境配置 python 开发语言 后端
在安装pythondlib时报错,首先碰到没有cmake的错误,安装完毕以后,遇到标题这个错误1.首先关闭与Python相关软件,如Pycharm,vscode等等2.打开安装python所在文件夹3.点击编辑4.将修改与写入打勾5.再次运行pip进行安装6.问题解决参考这里解决方案
LeetCode[位运算] - #137 Single Number II
Cwind
java Algorithm LeetCode 题解 位运算
原题链接:#137 Single Number II
要求:
给定一个整型数组,其中除了一个元素之外,每个元素都出现三次。找出这个元素
注意:算法的时间复杂度应为O(n),最好不使用额外的内存空间
难度:中等
分析:
与#136类似,都是考察位运算。不过出现两次的可以使用异或运算的特性 n XOR n = 0, n XOR 0 = n,即某一
《JavaScript语言精粹》笔记
aijuans
JavaScript
0、JavaScript的简单数据类型包括数字、字符创、布尔值(true/false)、null和undefined值,其它值都是对象。
1、JavaScript只有一个数字类型,它在内部被表示为64位的浮点数。没有分离出整数,所以1和1.0的值相同。
2、NaN是一个数值,表示一个不能产生正常结果的运算结果。NaN不等于任何值,包括它本身。可以用函数isNaN(number)检测NaN,但是
你应该更新的Java知识之常用程序库
Kai_Ge
java
在很多人眼中,Java 已经是一门垂垂老矣的语言,但并不妨碍 Java 世界依然在前进。如果你曾离开 Java,云游于其它世界,或是每日只在遗留代码中挣扎,或许是时候抬起头,看看老 Java 中的新东西。
Guava
Guava[gwɑ:və],一句话,只要你做Java项目,就应该用Guava(Github)。
guava 是 Google 出品的一套 Java 核心库,在我看来,它甚至应该
HttpClient
120153216
httpclient
/**
* 可以传对象的请求转发,对象已流形式放入HTTP中
*/
public static Object doPost(Map<String,Object> parmMap,String url)
{
Object object = null;
HttpClient hc = new HttpClient();
String fullURL
Django model字段类型清单
2002wmj
django
Django 通过 models 实现数据库的创建、修改、删除等操作,本文为模型中一般常用的类型的清单,便于查询和使用: AutoField:一个自动递增的整型字段,添加记录时它会自动增长。你通常不需要直接使用这个字段;如果你不指定主键的话,系统会自动添加一个主键字段到你的model。(参阅自动主键字段) BooleanField:布尔字段,管理工具里会自动将其描述为checkbox。 Cha
在SQLSERVER中查找消耗CPU最多的SQL
357029540
SQL Server
返回消耗CPU数目最多的10条语句
SELECT TOP 10
total_worker_time/execution_count AS avg_cpu_cost, plan_handle,
execution_count,
(SELECT SUBSTRING(text, statement_start_of
Myeclipse项目无法部署,Undefined exploded archive location
7454103
eclipse MyEclipse
做个备忘!
错误信息为:
Undefined exploded archive location
原因:
在工程转移过程中,导致工程的配置文件出错;
解决方法:
 
GMT时间格式转换
adminjun
GMT 时间转换
普通的时间转换问题我这里就不再罗嗦了,我想大家应该都会那种低级的转换问题吧,现在我向大家总结一下如何转换GMT时间格式,这种格式的转换方法网上还不是很多,所以有必要总结一下,也算给有需要的朋友一个小小的帮助啦。
1、可以使用
SimpleDateFormat SimpleDateFormat
EEE-三位星期
d-天
MMM-月
yyyy-四位年
Oracle数据库新装连接串问题
aijuans
oracle数据库
割接新装了数据库,客户端登陆无问题,apache/cgi-bin程序有问题,sqlnet.log日志如下:
Fatal NI connect error 12170.
VERSION INFORMATION: TNS for Linux: Version 10.2.0.4.0 - Product
回顾java数组复制
ayaoxinchao
java 数组
在写这篇文章之前,也看了一些别人写的,基本上都是大同小异。文章是对java数组复制基础知识的回顾,算是作为学习笔记,供以后自己翻阅。首先,简单想一下这个问题:为什么要复制数组?我的个人理解:在我们在利用一个数组时,在每一次使用,我们都希望它的值是初始值。这时我们就要对数组进行复制,以达到原始数组值的安全性。java数组复制大致分为3种方式:①for循环方式 ②clone方式 ③arrayCopy方
java web会话监听并使用spring注入
bewithme
Java Web
在java web应用中,当你想在建立会话或移除会话时,让系统做某些事情,比如说,统计在线用户,每当有用户登录时,或退出时,那么可以用下面这个监听器来监听。
import java.util.ArrayList;
import java.ut
NoSQL数据库之Redis数据库管理(Redis的常用命令及高级应用)
bijian1013
redis 数据库 NoSQL
一 .Redis常用命令
Redis提供了丰富的命令对数据库和各种数据库类型进行操作,这些命令可以在Linux终端使用。
a.键值相关命令
b.服务器相关命令
1.键值相关命令
&
java枚举序列化问题
bingyingao
java 枚举 序列化
对象在网络中传输离不开序列化和反序列化。而如果序列化的对象中有枚举值就要特别注意一些发布兼容问题:
1.加一个枚举值
新机器代码读分布式缓存中老对象,没有问题,不会抛异常。
老机器代码读分布式缓存中新对像,反序列化会中断,所以在所有机器发布完成之前要避免出现新对象,或者提前让老机器拥有新增枚举的jar。
2.删一个枚举值
新机器代码读分布式缓存中老对象,反序列
【Spark七十八】Spark Kyro序列化
bit1129
spark
当使用SparkContext的saveAsObjectFile方法将对象序列化到文件,以及通过objectFile方法将对象从文件反序列出来的时候,Spark默认使用Java的序列化以及反序列化机制,通常情况下,这种序列化机制是很低效的,Spark支持使用Kyro作为对象的序列化和反序列化机制,序列化的速度比java更快,但是使用Kyro时要注意,Kyro目前还是有些bug。
Spark
Hybridizing OO and Functional Design
bookjovi
erlang haskell
推荐博文:
Tell Above, and Ask Below - Hybridizing OO and Functional Design
文章中把OO和FP讲的深入透彻,里面把smalltalk和haskell作为典型的两种编程范式代表语言,此点本人极为同意,smalltalk可以说是最能体现OO设计的面向对象语言,smalltalk的作者Alan kay也是OO的最早先驱,
Java-Collections Framework学习与总结-HashMap
BrokenDreams
Collections
开发中常常会用到这样一种数据结构,根据一个关键字,找到所需的信息。这个过程有点像查字典,拿到一个key,去字典表中查找对应的value。Java1.0版本提供了这样的类java.util.Dictionary(抽象类),基本上支持字典表的操作。后来引入了Map接口,更好的描述的这种数据结构。
&nb
读《研磨设计模式》-代码笔记-职责链模式-Chain Of Responsibility
bylijinnan
java 设计模式
声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
/**
* 业务逻辑:项目经理只能处理500以下的费用申请,部门经理是1000,总经理不设限。简单起见,只同意“Tom”的申请
* bylijinnan
*/
abstract class Handler {
/*
Android中启动外部程序
cherishLC
android
1、启动外部程序
引用自:
http://blog.csdn.net/linxcool/article/details/7692374
//方法一
Intent intent=new Intent();
//包名 包名+类名(全路径)
intent.setClassName("com.linxcool", "com.linxcool.PlaneActi
summary_keep_rate
coollyj
SUM
BEGIN
/*DECLARE minDate varchar(20) ;
DECLARE maxDate varchar(20) ;*/
DECLARE stkDate varchar(20) ;
DECLARE done int default -1;
/* 游标中 注册服务器地址 */
DE
hadoop hdfs 添加数据目录出错
daizj
hadoop hdfs 扩容
由于原来配置的hadoop data目录快要用满了,故准备修改配置文件增加数据目录,以便扩容,但由于疏忽,把core-site.xml, hdfs-site.xml配置文件dfs.datanode.data.dir 配置项增加了配置目录,但未创建实际目录,重启datanode服务时,报如下错误:
2014-11-18 08:51:39,128 WARN org.apache.hadoop.h
grep 目录级联查找
dongwei_6688
grep
在Mac或者Linux下使用grep进行文件内容查找时,如果给定的目标搜索路径是当前目录,那么它默认只搜索当前目录下的文件,而不会搜索其下面子目录中的文件内容,如果想级联搜索下级目录,需要使用一个“-r”参数:
grep -n -r "GET" .
上面的命令将会找出当前目录“.”及当前目录中所有下级目录
yii 修改模块使用的布局文件
dcj3sjt126com
yii layouts
方法一:yii模块默认使用系统当前的主题布局文件,如果在主配置文件中配置了主题比如: 'theme'=>'mythm', 那么yii的模块就使用 protected/themes/mythm/views/layouts 下的布局文件; 如果未配置主题,那么 yii的模块就使用 protected/views/layouts 下的布局文件, 总之默认不是使用自身目录 pr
设计模式之单例模式
come_for_dream
设计模式 单例模式 懒汉式饿汉式 双重检验锁失败 无序写入
今天该来的面试还没来,这个店估计不会来电话了,安静下来写写博客也不错,没事翻了翻小易哥的博客甚至与大牛们之间的差距,基础知识不扎实建起来的楼再高也只能是危楼罢了,陈下心回归基础把以前学过的东西总结一下。
*********************************
8、数组
豆豆咖啡
二维数组 数组 一维数组
一、概念
数组是同一种类型数据的集合。其实数组就是一个容器。
二、好处
可以自动给数组中的元素从0开始编号,方便操作这些元素
三、格式
//一维数组
1,元素类型[] 变量名 = new 元素类型[元素的个数]
int[] arr =
Decode Ways
hcx2013
decode
A message containing letters from A-Z is being encoded to numbers using the following mapping:
'A' -> 1
'B' -> 2
...
'Z' -> 26
Given an encoded message containing digits, det
Spring4.1新特性——异步调度和事件机制的异常处理
jinnianshilongnian
spring 4.1
目录
Spring4.1新特性——综述
Spring4.1新特性——Spring核心部分及其他
Spring4.1新特性——Spring缓存框架增强
Spring4.1新特性——异步调用和事件机制的异常处理
Spring4.1新特性——数据库集成测试脚本初始化
Spring4.1新特性——Spring MVC增强
Spring4.1新特性——页面自动化测试框架Spring MVC T
squid3(高命中率)缓存服务器配置
liyonghui160com
系统:centos 5.x
需要的软件:squid-3.0.STABLE25.tar.gz
1.下载squid
wget http://www.squid-cache.org/Versions/v3/3.0/squid-3.0.STABLE25.tar.gz
tar zxf squid-3.0.STABLE25.tar.gz &&
避免Java应用中NullPointerException的技巧和最佳实践
pda158
java
1) 从已知的String对象中调用equals()和equalsIgnoreCase()方法,而非未知对象。 总是从已知的非空String对象中调用equals()方法。因为equals()方法是对称的,调用a.equals(b)和调用b.equals(a)是完全相同的,这也是为什么程序员对于对象a和b这么不上心。如果调用者是空指针,这种调用可能导致一个空指针异常
Object unk
如何在Swift语言中创建http请求
shoothao
http swift
概述:本文通过实例从同步和异步两种方式上回答了”如何在Swift语言中创建http请求“的问题。
如果你对Objective-C比较了解的话,对于如何创建http请求你一定驾轻就熟了,而新语言Swift与其相比只有语法上的区别。但是,对才接触到这个崭新平台的初学者来说,他们仍然想知道“如何在Swift语言中创建http请求?”。
在这里,我将作出一些建议来回答上述问题。常见的
Spring事务的传播方式
uule
spring事务
传播方式:
新建事务
required
required_new - 挂起当前
非事务方式运行
supports
&nbs