一、网络爬虫的定义
网络爬虫,即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 抓取小红书
小五咔咔咔
python 开发语言
python相关学习资料:https://edu.51cto.com/video/3832.htmlhttps://edu.51cto.com/video/4102.htmlhttps://edu.51cto.com/video/1158.htmlPython抓取小红书数据的科普文章小红书是一个流行的社交电商平台,用户可以分享购物心得、生活点滴等。本文将介绍如何使用Python语言抓取小红书的数据
selenium后续!!
paid槮
selenium 测试工具
小项目案例:实现批量下载网页中的资源根据15.3.2小节中的返回网页内容可知,用户只有获取了网页中的图片url才可以将图片下载到*在使用selenium库渲染网页后,可直接通过正则表达式过滤出指定的网页图片,从而实现批量下载接下来以此为思路来实现一个小项目案例。项目任务实现批量下载人民邮电出版社官网中与Python相关的图书封面图片。项目实步骤步骤1,获取人民邮电出版社官网中与Python相关的图
python相关内容二
湫默
python 开发语言
1.技术面试题(1)详细描述单调栈的工作原理和应用场景答:工作原理:维护一个栈结构,栈中元素保持单调递增或单调递减的顺序。遍历数据时,新元素入栈前,弹出栈顶所有不满足单调关系的元素,再将新元素入栈,确保栈的单调性。应用场景:解决下一个元素更大的问题,如数组中后面一个元素比前面一个入栈的元素大,则需要上一个元素出栈,然后大的那个元素入栈。(2)详细描述单调队列的工作原理和应用场景答:工作原理:维护队
python namedtuple转为dict
链池
python 开发语言
python相关学习资料:搭建私人助理大模型需要什么环境?006_指法标准_键盘正位_你好世界_hello_world_单引号_双引号一张图生成指定动作的动态视频,MagicAnimate本地部署Pythonnamedtuple转为dict的方法作为一名经验丰富的开发者,我很高兴能够帮助刚入行的小白们解决编程问题。今天,我们将一起学习如何将Python中的namedtuple转换为dict。这个过
Python常考面试题汇总(附答案)
TT图图
面试 职场和发展
写在前面本文面向中高级Python开发,太基本的题目不收录。本文只涉及Python相关的面试题,关于网络、MySQL、算法等其他面试必考题会另外开专题整理。不是单纯的提供答案,抵制八股文!!更希望通过代码演示,原理探究等来深入讲解某一知识点,做到融会贯通。部分演示代码也放在了我的github的该目录下。语言基础篇Python的基本数据类型Python3中有六个标准的数据类型:Number(数字)(
Python基础---面试题汇总
软件测试凡哥
Python python 开发语言 面试 经验分享 程序人生
前言本文只涉及Python相关的面试题,面向中高级Python开发,太基本的题目不收录。更希望通过代码演示,原理探究等来深入讲解某一知识点,做到融会贯通。另外部分演示代码有兴趣的可以找我拿。语言基础篇Python的基本数据类型Python3中有六个标准的数据类型:Number(数字)(包括整型、浮点型、复数、布尔型等)String(字符串)List(列表)Tuple(元组)Set(集合)Dicti
python系列教程246——多态
人工智能AI技术
python系列教程 python 开发语言
朋友们,如需转载请标明出处:https://blog.csdn.net/jiangjunshow声明:在人工智能技术教学期间,不少学生向我提一些python相关的问题,所以为了让同学们掌握更多扩展知识更好地理解AI技术,我让助理负责分享这套python系列教程,希望能帮到大家!由于这套python教程不是由我所写(有时候有空也会参与编写),所以不如我的人工智能教程风趣幽默,学起来比较枯燥;但它的知
MCP实战:从零开始写基于 Python 的 MCP 服务(附源码)
项目源码地址:obsidian-mcp-python介绍现在mcp相关信息满天飞,但大多都在搞理论。不如动手搞个mcp服务,让它跑起来才能真正感受到mcp是个啥。另外,目前的免费教程大多数是用js/ts写的,python版本还真是少之又少。刚好自己第一个mcp服务是python写的,虽然小但也方便理解。重点即便今天搜了mcppython相关资料,依旧很少,那就水一篇吧。后续会系统写下如何基于fas
node-sass 安装报错 无python等情况
名字太难随便取了
sass 前端 css node-sass
问题原因国内使用npm安装node-sass时主要是由于node-sass需要在github上拉取文件,而国内是无法稳定连接github的。当github上无法拉去文件时,将会转为使用node在本地编译,这时会需要用到python,而非python相关使用者一般都会报错,报错内容与gyp和python相关。解决问题前置条件:有方式能连接到github作为非python使用者,我们不可能为此花费更多
python 银行支付接口
AIRSOSON空净卫士
python 开发语言
python相关学习资料:https://edu.51cto.com/video/4102.htmlhttps://edu.51cto.com/video/1158.htmlhttps://edu.51cto.com/video/3502.htmlPython银行支付接口科普在当今的数字时代,银行支付接口已经成为企业和个人进行在线交易的重要工具。Python,作为一种流行的编程语言,提供了丰富的库
python 爬美团
毛瑟国王
python 开发语言
python相关学习资料:美国禁用中国大学MATLAB快四年,国产替代完成了吗?一张图生成指定动作的动态视频,MagicAnimate本地部署GitLabCI/CD-pending的原因Python爬取美团数据教程作为一名刚入行的开发者,你可能对如何使用Python进行网络爬虫感到困惑。本文将指导你如何使用Python爬取美团网站的数据。我们将从基础开始,逐步深入,确保你能够理解并实现整个过程。爬
基于实战经验的 Python 代码交付质量检查清单
Dongwoo Jeong
数据库 前端 python Python
这篇文章是我基于近3年从事Python相关外包项目并交付代码的经验总结而成的,旨在提供一份提升Python代码质量的检查清单。由于这是基于我个人的外包经验编写的内容,因此与平时的文章不同,没有引用任何论文来源。因此,这篇文章将仅对粉丝公开,而不是完全公开。如果有任何不清楚的地方,请随时提问!本文档提供了在外包开发项目中交付代码时必须审查的质量标准。目标不仅是临时运行,而是确保可持续的维护和可重用的
Python量化——量化价值投资的必备技能
量化价值投资入门到精通
python 网络 开发语言 ai
Python量化——量化价值投资的必备技能关键词:Python量化、价值投资、金融数据分析、量化交易、投资策略、机器学习、回测系统摘要:本文深入探讨Python在量化价值投资中的应用,从基础概念到实际实现,全面解析如何利用Python构建量化投资系统。文章将详细介绍量化价值投资的核心原理、Python相关工具库、数据处理方法、策略建模和回测系统实现,并通过实际案例展示如何将价值投资理念转化为可执行
python 实现 http 请求 转发
自得仙
python http 开发语言 网络协议 网络
python相关学习资料:美国禁用中国大学MATLAB快四年,国产替代完成了吗?006_指法标准_键盘正位_你好世界_hello_world_单引号_双引号一张图生成指定动作的动态视频,MagicAnimate本地部署Python实现HTTP请求转发在网络编程中,HTTP请求转发是一种常见的技术,它允许一个服务器将接收到的HTTP请求转发给另一个服务器。这种方式可以用于负载均衡、缓存、安全等多种场
python docker库获取宿主机ip
斯嘉丽的脸
docker eureka 容器 运维 云原生
docker,python相关学习资料:https://edu.51cto.com/video/442.htmlhttps://edu.51cto.com/video/1158.htmlhttps://edu.51cto.com/video/4102.htmlPythonDocker库获取宿主机IP作为一名经验丰富的开发者,我很高兴能帮助刚入行的小白们解决实际问题。今天,我们将一起学习如何使用Py
【Python爬虫电商数据采集+数据分析】采集电商平台数据信息,并做可视化演示
电商数据girl
京东API接口 电商项目API接口测试 电商ERP项目接口 python 爬虫 数据分析 java 开发语言 数据库
前言随着电商平台的兴起,越来越多的人开始在网上购物。而对于电商平台来说,商品信息、价格、评论等数据是非常重要的。因此,抓取电商平台的商品信息、价格、评论等数据成为了一项非常有价值的工作。本文将介绍如何使用Python编写爬虫程序,抓取电商平台的商品信息、价格、评论等数据。给大家准备了一些Python相关的资料都可拿走一、准备工作在开始编写爬虫程序之前,我们需要准备一些工具和环境。二、分析目标网站在
ai python 面试_面试分享系列 | 17道Python面试题,让你在求职中无往不利
weixin_39558804
ai python 面试
今天给大家分享的是Python面试题系列的第一篇文章,后续我也会陆续整理Python相关的问题给大家,无论是求职者还是新人都可以通过面试题来考察自己的能力缺陷。1.Python中pass语句的作用是什么?pass语句什么也不做,一般作为占位符或者创建占位程序,pass语句不会执行任何操作。2.Python是如何进行类型转换的?Python提供了将变量或值从一种类型转换成另一种类型的内置函数。比如i
Python(27)Python字符串方法全解析:从基础操作到高效处理技巧
一个天蝎座 白勺 程序猿
python 开发语言
目录一、字符串处理核心价值1.1方法分类速查表二、六大核心方法深度解析2.1格式处理三剑客2.2查找替换全家桶2.3类型判断方法组三、五大高级应用场景3.1多语言文本处理3.2日志格式处理3.3模板字符串生成四、性能优化指南4.1方法性能对比4.2高效处理技巧五、常见错误与调试5.1编码问题5.2方法误用5.3不可变特性六、总结与最佳实践6.1方法选择决策树6.2企业级实施建议Python相关文章
Python(26)Python数据验证终极指南:从基础校验到高级技巧全覆盖
一个天蝎座 白勺 程序猿
python 开发语言
目录一、数据验证核心价值1.1核心方法对比表二、八大核心验证方法详解2.1数字验证三剑客2.2格式验证方法组三、六大实战验证场景3.1用户注册验证3.2金融数据清洗3.3多语言文本处理四、高级验证技巧4.1装饰器验证模式4.2组合验证策略五、常见错误与调试5.1编码问题导致验证失败5.2类型混淆错误5.3复合条件遗漏六、总结与最佳实践6.1验证策略选择树6.2企业级实施建议Python相关文章(推
使用python爬取百度搜索中关于python相关的数据信息
code_shenbing
python项目集合 python 爬虫
Python爬取百度搜索"Python"相关数据信息一、准备工作在开始爬取之前,需要了解以下几点:百度搜索有反爬机制,需要合理设置请求头百度搜索结果页面结构可能会变化需要遵守robots.txt协议(百度允许爬取搜索结果)二、基础爬取方案(使用requests+BeautifulSoup)importrequestsfrombs4importBeautifulSoupimportredefbaid
学python需要安装什么软件,学python需要用什么软件
2401_84668397
python
大家好,小编来为大家解答以下问题,学python需要安装什么软件,学python需要用什么软件,现在让我们一起来看看吧!前言编程这个东西是真的奇妙。对于懂得的人来说,会觉得这个工具是多么的好用、有趣,而对于小白来说,就如同大山一样。其实这个都可以理解,大家都是这样过来的。那么接下来就说一下python相关的东西吧,并说一下我对编程的理解。本人也是小白一名,如有不对的地方,还请各位大神指出~懒人目录
python相关编码规范
DXM0521
python新手教程 python 开发语言 机器学习 编辑器 人工智能 深度学习 自然语言处理
Python编码规范是一个指导Python代码风格和结构的规则集合。它有助于使你的代码易于阅读、易于维护和易于扩展。以下是一些常用的Python编码规范:一、代码编码格式一般来说,声明编码格式在脚本中是必需的。国际惯例,文件编码和Python编码格式全部为utf-8。例如:在Python代码的开头,要统⼀加上如下代码:#--coding:utf-8--如果Python源码文件没有声明编码格式,Py
python调整图片清晰度到1080p
二八二八
python 开发语言
Python相关视频讲解:python的or运算赋值用法用python编程Excel有没有用处?011_编程到底好玩在哪?查看python文件_输出py文件_cat_运行python文件_shel调整图片清晰度到1080p的Python实现在处理图片时,有时候我们需要调整其清晰度以适应特定的需求。比如,将一个低清晰度的图片调整为1080p高清晰度。在本文中,我们将介绍如何使用Python来实现这一
python清空redis缓存
我也卜知道
缓存 python redis oracle 数据库
Python相关视频讲解:python的or运算赋值用法用python编程Excel有没有用处?011_编程到底好玩在哪?查看python文件_输出py文件_cat_运行python文件_shel如何实现Python清空Redis缓存前言作为一名经验丰富的开发者,我将会教你如何实现Python清空Redis缓存。首先,我们需要了解整个流程,然后逐步进行操作。让我们开始吧!流程表格journeyti
Python(11)Python判断语句全面解析:从基础到高级模式匹配
一个天蝎座 白勺 程序猿
python 开发语言
目录一、条件逻辑的工程价值1.1真实项目中的逻辑判断1.2判断语句类型矩阵二、基础判断深度解析2.1多条件联合判断2.2类型安全判断三、模式匹配进阶应用3.1结构化数据匹配3.2对象模式匹配四、判断语句优化策略4.1逻辑表达式优化4.2性能对比测试五、典型应用场景实战5.1电商促销规则5.2数据清洗流程六、调试与错误处理6.1条件断点调试6.2防御性编程实践七、关键要点总结:Python相关文章
python 分布式任务调度平台
玫瑰妈妈
python 分布式 数据库 开发语言
python相关学习资料:搭建私人助理大模型需要什么环境?006_指法标准_键盘正位_你好世界_hello_world_单引号_双引号一张图生成指定动作的动态视频,MagicAnimate本地部署Python分布式任务调度平台实现指南作为一名刚入行的小白,你可能对如何实现一个Python分布式任务调度平台感到困惑。不用担心,我将通过这篇文章,带你一步步了解整个实现流程,并提供必要的代码示例和注释。
python 读取tif元数据
Faye Wang
python 开发语言
python相关学习资料:https://edu.51cto.com/video/3832.htmlhttps://edu.51cto.com/video/4102.htmlhttps://edu.51cto.com/video/4645.htmlPython读取TIFF图像元数据的科普TIFF(TaggedImageFileFormat)是一种广泛应用于图像存储的文件格式,它支持多种颜色和数据类
一文弄懂Python中的 if __name__ == __main__
xiaoweiwei99
面试 学习路线 阿里巴巴 python 开发语言 web安全 前端 javascript
1.引言在Python相关代码中,我们经常会遇到如下代码段:#stuffif__name__=="__main__":#dostuff本文将尽可能使用简单的样例来解释这里发生了什么,以及需要使用if__name__=="__main__"的情形。请注意,上述代码中name和main前后有2个下划线字符。闲话少说,我们直接开始吧!2.特殊变量当我们正常运行我们的Python脚本时,该脚本中的变量__
Python(8)Python操作系统接口完全指南:os模块核心功能与实战案例解析
一个天蝎座 白勺 程序猿
python 开发语言
目录背景一、os模块核心功能详解1.模块概览2.常用接口与语法二、六大实战案例案例1:递归创建多层目录案例2:批量重命名文件(按日期排序)案例3:安全删除空目录(避免误删)案例4:跨平台路径拼接(避免硬编码)案例5:遍历目录树并统计文件大小案例6:执行系统命令并捕获输出三、避坑指南与最佳实践1.常见错误2.安全建议3.性能优化四、总结注意事项Python相关文章(推荐)背景在Python开发中,
mac 怎么配置python 环境变量
花花鼓
macos python 开发语言
python相关学习资料:https://edu.51cto.com/video/4102.htmlhttps://edu.51cto.com/video/3502.htmlhttps://edu.51cto.com/video/1158.htmlMac上配置Python环境变量的详细方案在Mac操作系统上配置Python环境变量是一个常见的需求,尤其是对于开发者来说。本文将详细介绍如何在Mac上
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