每天刷开csdn的博客,看到⼀整个页⾯,其实对我⽽⾔,我只想看看访问量有没有上涨⽽已...于是萌⽣了⼀个想法:
想写⼀个爬⾍程序把csdn博客上边的访问量和评论数都爬下来。打算通过⽹络各种搜集资料,⾃学写Python代码。这次⾃学的历程,也打算及时的整理下来,发布在博客⾥。
/******************这是程序员风格的分割线******************/
2013.11.3_开⼯
据说Python并不难,看过了python的代码之后也觉得确实,
代码很清爽,相⽐起C/C++,JS,PHP来讲,python的代码看起来就是舒服。看了⼏段别⼈的爬⾍程序教程,还不太清楚Python的编译器是怎么处理代码的。每⼀句代码的分割似乎是通过换⾏,
像是if/else这样的多个语句在⼀起的,也没有看到⼤括号,⽽是像这样: [python]
1. import urllib, urllister 2. 3. def getURL(url): 4. try: 5. usock = urllib.urlopen(url) 6. except: 7. print 'get url excepton' 8. return [] 9. parser = urllister.URLLister() 10. parser.feed(usock.read()) 11. usock.close() 12. parser.close() 13. urls = parser.urls 14. return urls
变量的申明只需要在⽤的时候起个名字就好了,不⽤规定int, char, float....
我是⼀个从C语⾔转学来的乡下孩⼦..这么⾼端洋⽓上档次的定义⽅式真是惊了个呆。于是瞬间对Python好感倍增。
看了很多⼈的爬⾍教程,以及代码,还是没什么思路,今天没空了,等明天上⼿试试看。
2013.11.4_第⼀步⼤功告成
不错不错,今天试了试⽹上的教程,成功的把我的博客主页抓下来了。
中间还遇上些坎坷,不过先感谢⼀下
在他的百度空间 ⾥转载的博客
据所说转⾃ http://gae-django-cms.appspot.com 不过我这⾥似乎打不开这个⽹页..这篇⽂章真⼼的帮到了⼤忙,虽然⼩⼩吐槽⼀下排版不好..在这⾥系统的学到了Python爬⾍的⼊门部分。
这位博主请不要介意,我在这⾥帮你整理⼀下缩进,再整理⼀下代码⽅便⼤家吧~<--注意:⼀直到下⼀个此类似标记前的内容,均转⾃ 的博客,我只是做了整理-->
原⽂转⾃http://gae-django-cms.appspot.com/
这些脚本有⼀个共性,都是和web相关的,总要⽤到获取链接的⼀些⽅法,再加上simplecd这 个半爬⾍半⽹站的项⽬,累积不少爬⾍抓站的经验,在此总结⼀下,那么以后做东西也就不⽤重复劳动了。
1.最基本的抓站
[python]
1. import urllib2 2. content = urllib2.urlopen('http://XXXX').read()
2.使⽤代理服务器
这在某些情况下⽐较有⽤,⽐如IP被封了,或者⽐如IP访问的次数受到限制等等。 [python]
1. import urllib2 2. proxy_support = urllib2.ProxyHandler({'http':'http://XX.XX.XX.XX:XXXX'}) 3. opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler) 4. urllib2.install_opener(opener) 5. content = urllib2.urlopen('http://XXXX').read()
3.需要登录的情况
登录的情况⽐较⿇烦我把问题拆分⼀下:
3.1 cookie的处理 [python]
1. import urllib2, cookielib 2. cookie_support= urllib2.HTTPCookieProcessor(cookielib.CookieJar()) 3. opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler) 4. urllib2.install_opener(opener) 5. content = urllib2.urlopen('http://XXXX').read()
是的没错,如果想同时⽤代理和cookie,那就加⼊proxy_support然后operner改为 [python]
1. opener = urllib2.build_opener(proxy_support, cookie_support, urllib2.HTTPHandler)
3.2 表单的处理
登录必要填表,表单怎么填?⾸先利⽤⼯具截取所要填表的内容
⽐如我⼀般⽤firefox+httpfox插件来看看⾃⼰到底发送了些什么包
这个我就举个例⼦好了,以verycd为例,先找到⾃⼰发的POST请求,以及POST表单项:
可以看到verycd的话需要填username,password,continueURI,fk,login_submit这⼏项,其中fk是随机⽣ 成的(其实不太随机,看上去像是把epoch时间经过简单的编码⽣成的),需要从⽹页获取,也就是说得先访问⼀次⽹页,⽤正则表达式等⼯具截取返回数据中 的fk项。continueURI顾名思义可以随便写,login_submit是固定的,这从源码可以看出。还有username,password那 就很显然了。 -
好的,有了要填写的数据,我们就要⽣成postdata [python]
1. import urllib 2. postdata=urllib.urlencode({ 3. 'username':'XXXXX', 4. 'password':'XXXXX', 5. 'continueURI':'http://www.verycd.com/', 6. 'fk':fk, 7. 'login_submit':'登录' 8. })
然后⽣成http请求,再发送请求: [python]
1. req = urllib2.Request( 2. url = 'http://secure.verycd.com/signin/*/http://www.verycd.com/', 3. data = postdata) 4. result = urllib2.urlopen(req).read()
3.3 伪装成浏览器访问
某些⽹站反感爬⾍的到访,于是对爬⾍⼀律拒绝请求
这时候我们需要伪装成浏览器,这可以通过修改http包中的header来实现 [python]
1. headers = { 2. 'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6' 3. } 4. req = urllib2.Request( 5. url = 'http://secure.verycd.com/signin/*/http://www.verycd.com/', 6. data = postdata, 7. headers = headers 8. )
3.4 反”反盗链”
某些站点有所谓的反盗链设置,其实说穿了很简单,就是检查你发送请求的header⾥⾯,referer站点是不是他⾃⼰,所以我们只需要像3.3⼀样, 把headers的referer改成该⽹站即可,以⿊幕著称地cnbeta为例: [python]
1. #... 2. headers = { 3. 'Referer':'http://www.cnbeta.com/articles' 4. } 5. #...
headers是⼀个dict数据结构,你可以放⼊任何想要的header,来做⼀些伪装。例如,有些⾃作聪明的⽹站总喜欢窥⼈隐私,别⼈通过代理 访问,他偏偏要读取header中的X-Forwarded-For来看看⼈家的真实IP,没话说,那就直接把X-Forwarde-For改了吧,可以 改成随便什么好玩的东东来欺负欺负他,呵呵。 -
3.5 终极绝招
有时候即使做了3.1-3.4,访问还是会被据,那么没办法,⽼⽼实实把httpfox中看到的headers全都写上,那⼀般也就⾏了。
再不⾏,那就只能⽤终极绝招了,selenium直 接控制浏览器来进⾏访问,只要浏览器可以做到的,那么它也可以做到。类似的还有pamie,watir,等等等等。 -
4.多线程并发抓取
单线程太慢的话,就需要多线程了,这⾥给个简单的线程池模板这个程序只是简单地打印了1-10,但是可以看出是并发地。 [python]
1. from threading import Thread 2. from Queue import Queue 3. from time import sleep 4. #q是任务队列 5. #NUM是并发线程总数 6. #JOBS是有多少任务 7. q = Queue() 8. NUM = 2 9. JOBS = 10 10. #具体的处理函数,负责处理单个任务 11. def do_somthing_using(arguments): 12. print arguments 13. #这个是⼯作进程,负责不断从队列取数据并处理 14. def working(): 15. while True: 16. arguments = q.get() 17. do_somthing_using(arguments) 18. sleep(1) 19. q.task_done() 20. #fork NUM个线程等待队列 21. for i in range(NUM): 22. t = Thread(target=working) 23. t.setDaemon(True) 24. t.start() 25. #把JOBS排⼊队列 26. for i in range(JOBS): 27. q.put(i) 28. #等待所有JOBS完成 29. q.join()
5.验证码的处理
碰到验证码咋办?这⾥分两种情况处理:
1.google那种验证码, 凉拌
2.简单的验证码:
字符个数有限,只使⽤了简单的平移或旋转加噪⾳⽽没有扭曲的,这种还是有可能可以处理的,⼀般思路是旋转的转回来,噪⾳去掉,然后划分 单个字符,划分好了以后再通过特征提取的⽅法(例如PCA) 降维并⽣成特征库,然后把验证码和特征库进⾏⽐较。这个⽐较复杂,⼀篇博⽂是说不完的,这⾥就不展开了,具体做法请弄本相关教科书好好研究⼀下。
3.事实上有些验证码还是很弱的,
这⾥就不点名了,反正我通过2的⽅法提取过准确度⾮常⾼的验证码,所以2事实上是可⾏的。
6.总结
基本上我遇到过的所有情况,⽤以上⽅法都顺利解决了。
<--注意:以上内容均转⾃ 的博客,我只是做了整理,以下内容为本⼈原创-->
利⽤这篇博客⾥的例⼦,我先模仿了⼀个⾃⼰的Python爬⾍。 [python]
1. import urllib2 2. content = urllib2.urlopen('http://blog.csdn.net/yuri_4_vera').read()
我是⽤Sublime Text2 作为编辑器,直接利⽤Mac⾥安装的Python编译的,报出如下错误:urllib2.HTTPError: HTTP Error 403: Forbidden
嗯~果然没错,csdn是反感爬⾍的,可是我只是想⽅便的知道我的访问量和评论数嘛...于是采⽤博客⾥的3.3⽅法,把urllib2伪装成浏览器访问,我的代码就变成了这样: [python]
1. import urllib2 2. 3. headers = { 4. 'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6' 5. } 6. req = urllib2.Request( 7. url = 'http://blog.csdn.net/yuri_4_vera', 8. headers = headers 9. ) 10. 11. content = urllib2.urlopen(req).read() 12. print content
成功的抓下来我的整个博客主页有⽊有!print输出的全是HTML的代码有⽊有!看到哗啦啦的代码刷下去太舒服了..学校课程真紧..操作系统、数据挖掘两个⼤实验..今⼉就到这⼉吧。
就不附上主页的代码了,如果⽤Chrome的话,可以右键审查元素。Safari的话可以在偏好设置⾥勾选“在菜单栏⾥显⽰开发菜单”,就可以右
键检查元素了。
主要是需要这⼀部分的内容: [html]
1. 6. 7. 2.
2013.11.5_抓到了!
抓到了!先看看抓到的东西长什么样:
最底下的部分就是抓出来的。
昨天已经抓到了整个主页,今天主要是想办法把需要⽤的这部分内容挑出来。昨晚上简单查了下,据说需要使⽤正则表达式,听到这个名字只觉得⽿熟不觉得有数...
问了问同学,发觉似乎是离散数学还是什么课⾥讲过的⼀个部分……上课不听课的默默去⾕歌了..到了中午回来,还是不知道要怎么具体操作,后来在搜到这样⼀篇⽂章
其中有这么⼀个部分
受益匪浅!尝试了⼀下 [python]
1. result = re.findall(r'(?<=\\).+?(?=\\<\\/ul\\>)',content)
很显然..出错了。
Python的转义字符还是不太懂的样⼦..后来尝试
[python]
1. result = re.findall(r'(?<=).+?(?=\\
)',content) 只能筛选出来“[]”,很奇怪……
后来就随便⼀试,发现了 [python]
1. result = re.findall(r'(?<=
1. 访问:308次 2. 积分:41分 3. 排名:千⾥之外 4. 原创:4篇 5. 转载:0篇 6. 译⽂:0篇 7. 评论:1条
附上代码: [python]
1. import urllib2 2. import re 3.
4. headers = {
5. 'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6' 6. }
7. req = urllib2.Request(
8. url = 'http://blog.csdn.net/yuri_4_vera', 9. headers = headers 10. ) 11.
12. content = urllib2.urlopen(req).read()
13. result = re.findall(r'(?<=
14.
15. for x in xrange(0,7): 16. print result[x] 17. pass
最近忙别的事情,这⾥再加⼀句替换,就可以把烦⼈的和去掉,⽤php抓的那篇博⽂⾥我有加,python最近还没空继续钻...
/************2013-12-3**************/更新:
感谢@laochx的反馈,对于编码问题的解决,可以添加以下代码: [python]
1. content = urllib2.urlopen(req).read() 2. content=content.decode(\"utf8\")
3. result = re.findall(r'(?<=
因篇幅问题不能全部显示,请点此查看更多更全内容