最全Python爬虫总结(转载)

[html] view plain copy

 
  1. 最近总是要爬取一些东西,索性就把Python爬虫的相关内容都总结起来了,自己多动手还是好。  
(1)普通的内容爬取
(2)保存爬取的图片/视频和文件和网页
(3)普通模拟登录
(4)处理验证码登录
(5)爬取js网站
(6)全网爬虫
(7)某个网站的站内所有目录爬虫
(8)多线程 
(9)爬虫框架Scrapy   


一,普通的内容爬取
[html] view plain copy
 
  1. #coding=utf-8  
  2. import urllib    
  3. import urllib2    
  4. url = 'http://www.dataanswer.top'    
  5. headers = {   
  6.     'Host':'www.dataanswer.top',  
  7.     'User-Agent':'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:31.0) Gecko/20100101 Firefox/31.0',  
  8.     #'Accept':'application/json, text/javascript, */*; q=0.01',  
  9.     #'Accept-Language':'zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3',  
  10.     #'Accept-Encoding':'gzip,deflate',  
  11.     #'Referer':'http://www.dataanswer.top'  
  12. }     
  13. request = urllib2.Request(url,headers=headers)    
  14. response = urllib2.urlopen(request)    
  15. page = response.read()  
  16. print page  
二,保存爬取的图片/视频和文件和网页
#图片/视频和文件和网页的地址抓取下来后,利用模块urllib里的urlretrieve()方法下载下来:
[html] view plain copy
 
  1. #coding=utf-8  
  2. import urllib    
  3. import urllib2    
  4. import os  
  5. def getPage(url):       
  6.     request = urllib2.Request(url)    
  7.         response = urllib2.urlopen(request)    
  8.         return response.read()    
  9.   
  10.   
  11. url='http://www.dataanswer.top/'    
  12. result=getPage(url)    
  13. file_name='test.doc'  
  14. file_path='doc'  
  15. if os.path.exists(file_path) == False:  
  16.     os.makedirs(file_path)  
  17. local=os.path.join(file_path,file_name)  
  18. f = open(local,"w+")    
  19. f.write(result)   
  20. f.close()  
  21.   
  22.   
  23. #coding=utf-8  
  24. import urllib    
  25. import urllib2    
  26. import os  
  27. def getPage(url):       
  28.     request = urllib2.Request(url)    
  29.         response = urllib2.urlopen(request)    
  30.         return response.read()    
  31.   
  32.   
  33. url='http://www.dataanswer.top/'  #把该地址改成图片/文件/视频/网页的地址即可  
  34. result=getPage(url)    
  35. file_name='test.doc'  
  36. file_path='doc'  
  37. if os.path.exists(file_path) == False:  
  38.     os.makedirs(file_path)  
  39. local=os.path.join(file_path,file_name)  
  40. urllib.urlretrieve(url,local)  
三,普通模拟登录
[html] view plain copy
 
  1. import urllib  
  2. import urllib2  
  3. import cookielib  
  4.    
  5. filename = 'cookie.txt'  
  6. #声明一个MozillaCookieJar对象实例来保存cookie,之后写入文件  
  7. cookie = cookielib.MozillaCookieJar(filename)  
  8. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))  
  9. postdata = urllib.urlencode({  
  10. 'name':'春天里',  
  11. 'pwd':'1222222'  
  12. })  
  13. #登录的URL  
  14. loginUrl = 'http://www.dataanswer.top/LoginService?action=tologin'  
  15. #模拟登录,并把cookie保存到变量  
  16. result = opener.open(loginUrl,postdata)  
  17. #保存cookie到cookie.txt中  
  18. cookie.save(ignore_discard=True, ignore_expires=True)  
  19. #利用cookie请求访问另一个网址  
  20. gradeUrl = 'http://www.dataanswer.top/LoginService?action=myHome'  
  21. #请求访问  
  22. result = opener.open(gradeUrl)  
  23. print result.read()  
四,处理验证码登录
#先把验证码图片下载下来保存,再人工读入
[html] view plain copy
 
  1. #coding=utf-8  
  2. import sys, time, os, re  
  3. import urllib, urllib2, cookielib  
  4. loginurl = 'https://www.douban.com/accounts/login'  
  5. cookie = cookielib.CookieJar()  
  6. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))  
  7. params = {  
  8. "form_email":"13161055481",  
  9. "form_password":"wwwwwww",  
  10. "source":"index_nav" #没有的话登录不成功  
  11. }  
  12. #从首页提交登录  
  13. response=opener.open(loginurl)  
  14. #验证成功跳转至登录页  
  15. print(response.geturl())  
  16. if response.geturl() == "https://www.douban.com/accounts/login":  
  17.     html=response.read()  
  18.     print(html)  
  19.     #验证码图片地址--图片地址加密怎么办???  
  20.     imgurl=re.search('<img id="captcha_image" src="(.+?)" alt="captcha" class="captcha_image"/>', html)  
  21.     print(imgurl)  
  22.     if imgurl:  
  23.             url=imgurl.group(1)  
  24.             #将图片保存至同目录下  
  25.             res=urllib.urlretrieve(url,'v.jpg')  
  26.             #获取captcha-id参数  
  27.             captcha=re.search('<input type="hidden" name="captcha-id" value="(.+?)"/>',html)  
  28.             if captcha:  
  29.                 vcode=raw_input('请输入图片上的验证码:')  
  30.                 params["captcha-solution"]=vcode  
  31.                 params["captcha-id"]=captcha.group(1)  
  32.                 params["user_login"]="登录"  
  33.                 #提交验证码验证  
  34.                 response=opener.open(loginurl, urllib.urlencode(params))  
  35.                 ''' 登录成功跳转至首页 '''  
  36.                 if response.geturl() == "https://www.douban.com/":  
  37.                     print 'login success ! '  
  38.                     print '准备进行发帖'  
  39.                     addtopicurl="http://www.douban.com/group/python/new_topic"  
  40.                     res=opener.open(addtopicurl)  
  41.                     html=res.read()  
  42.             else:  
  43.                 print("Fail3")  
  44.         else:  
  45.             print("Fail2")  
  46.     else:  
  47.         print("Fail1")  
  48. else:  
  49.     print("Fail0")  
五,爬取js网站
#利用selenium模拟浏览器,结合html的解析
[html] view plain copy
 
  1. #coding=utf-8  
  2. #1、安装 python-pip  
  3. #sudo apt-get install python-pip  
  4. #2、安装selenium  
  5. #sudo pip install -U selenium  
  6.   
  7.   
  8. from selenium import webdriver  
  9. driver = webdriver.Firefox()   
  10. driver.get('http://www.newsmth.net/nForum/#!article/Intern/206790')  
  11. html=driver.page_source.encode('utf-8','ignore') #这个函数获取页面的html  
  12. print(html)  
  13. driver.close()  

六,全网爬虫
#广度优先,模拟爬取队列
[html] view plain copy
 
  1. #coding=utf-8  
  2. """  
  3. 全网爬取所有链接,包括外链--广度优先  
  4. """  
  5. import urllib2  
  6. import re  
  7. from bs4 import BeautifulSoup  
  8. import time  
  9.   
  10.   
  11. #爬虫开始的时间  
  12. t=time.time()  
  13. #设置的暂停爬取条数  
  14. N_STOP=10  
  15.   
  16.   
  17. #存放已经爬取过的url  
  18. CHECKED_URL=[]  
  19. #存放待爬取的url  
  20. CHECKING_URL=[]  
  21. #存放连接失败的url  
  22. FAIL_URL=[]  
  23. #存放不能连接的url  
  24. ERROR_URL=[]  
  25. #失败后允许连接的次数  
  26. RETRY=3  
  27. #连接超时时间  
  28. TIMEOUT=20  
  29.   
  30.   
  31. class url_node:  
  32.     def __init__(self,url):  
  33.         """  
  34.         url节点初始化  
  35.         :param url:String 当前url  
  36.         """  
  37.         self.url=url  
  38.         self.content=''  
  39.   
  40.   
  41.     def __is_connectable(self):  
  42.         """  
  43.         检验url是否可以连接  
  44.         """  
  45.         #在允许连接次数下连接  
  46.         for i in range(RETRY):  
  47.             try:  
  48.                 #打开url没有报错,则表示可连接  
  49.                 response=urllib2.urlopen(self.url,timeout=TIMEOUT)  
  50.                 return True  
  51.             except:  
  52.                 #如果在尝试允许连接次数下报错,则不可连接  
  53.                 if i==RETRY-1:  
  54.                     return False  
  55.   
  56.   
  57.     def get_next(self):  
  58.         """  
  59.         获取爬取该页中包含的其他所有的url  
  60.         """  
  61.         soup=BeautifulSoup(self.content)  
  62.         #******************在此处可以从网页中解析你想要的内容************************************  
  63.         next_urls=soup.findAll('a')  
  64.         if len(next_urls)!=0:  
  65.             for link in next_urls:  
  66.                 tmp_url=link.get('href')  
  67.                 #如果url不在爬取过的列表中也不在待爬取列表中则把其放到待爬列表中(没有确保该url有效)  
  68.                 if tmp_url not in CHECKED_URL and tmp_url not in CHECKING_URL:  
  69.                     CHECKING_URL.append(tmp_url)  
  70.           
  71.     def run(self):  
  72.         if self.url:  
  73.             if self.__is_connectable():  
  74.                 try:  
  75.                     #获取爬取页面的所有内容  
  76.                     self.content=urllib2.urlopen(self.url,timeout=TIMEOUT).read()  
  77.                     #从该页面中获取url  
  78.                     self.get_next()  
  79.   
  80.   
  81.                 except:  
  82.                     #把连接失败的存放起来  
  83.                     FAIL_URL.append(self.url)  
  84.                     print('[!]Connect Failed')  
  85.             else:  
  86.                 #把不能连接的存放起来  
  87.                 ERROR_URL.append(self.url)  
  88.         else:  
  89.             print("所给的初始url有问题!")             
  90.   
  91.   
  92. if __name__=='__main__':  
  93.     #把初始的url放到待爬的列表中  
  94.     CHECKING_URL.append('http://www.36dsj.com/')  
  95.     #不断的从待爬的列表中获取url进行爬取  
  96.     ff=open("Mytest.txt",'w')  
  97.     i=0  
  98.     for url in CHECKING_URL:  
  99.         #对该url进行爬取  
  100.         url_node(url).run()  
  101.         #存放已经爬取过的url  
  102.         CHECKED_URL.append(url)   
  103.         #删除CHECKING_URL中已经爬取过的url  
  104.         CHECKING_URL.remove(url)  
  105.   
  106.   
  107.         i+=1  
  108.         if i==N_STOP:  
  109.             #打出停止时的url,下次可以把该url作为初始继续  
  110.             print url  
  111.             print("爬取过的列表长度:%d") % len(CHECKED_URL)  
  112.             print("待爬取的列表长度:%d") % len(CHECKING_URL)  
  113.             print("连接失败的列表长度:%d") % len(FAIL_URL)  
  114.             print("不能连接的列表长度:%d") % len(ERROR_URL)  
  115.             break  
  116.     ff.close()  
  117.     print("time:%d s") % (time.time()-t)      

七,某个网站的站内所有目录爬虫
#把缩写的站内网址还原
[html] view plain copy
 
  1. #coding=utf-8  
  2. """  
  3. 爬取同一个网站所有的url,不包括外链  
  4. """  
  5. import urllib2  
  6. import re  
  7. from bs4 import BeautifulSoup  
  8. import time  
  9.   
  10. t=time.time()  
  11.   
  12. HOST=''  
  13. CHECKED_URL=[]  
  14. CHECKING_URL=[]  
  15. RESULT=[]  
  16. RETRY=3  
  17. TIMEOUT=20  
  18.   
  19. class url_node:  
  20.     def __init__(self,url):  
  21.         """  
  22.         url节点初始化  
  23.         :param url:String 当前url  
  24.         """  
  25.         self.url=self.handle_url(url,is_next_url=False)  
  26.         self.next_url=[]  
  27.         self.content=''  
  28.   
  29.   
  30.     def handle_url(self,url,is_next_url=True):  
  31.         """  
  32.         将所有的url处理成标准形式  
  33.         """  
  34.         global CHECKED_URL  
  35.         global CHECKING_URL  
  36.   
  37.         #去掉尾部的‘/’  
  38.         url=url[0:len(url)-1] if url.endswith('/') else url  
  39.   
  40.         if url.find(HOST)==-1:  
  41.             if not url.startswith('http'):  
  42.                 url='http://'+HOST+url if url.startswith('/') else 'http://'+HOST+'/'+url  
  43.             else:  
  44.                 #如果含有http说明是外链,url的host不是当前的host,返回空  
  45.                 return  
  46.         else:  
  47.             if not url.startswith('http'):  
  48.                 url='http://'+url  
  49.   
  50.   
  51.         if is_next_url:  
  52.             #下一层url放入待检测列表  
  53.             if url not in CHECKING_URL:  
  54.                 CHECKING_URL.append(url)  
  55.         else:  
  56.             #对于当前需要检测的url将参数都替换为1,然后加入规则表  
  57.             #参数相同类型不同的url只检测一次  
  58.             rule=re.compile(r'=.*?\&|=.*?$')  
  59.             result=re.sub(rule,'=1&',url)  
  60.             if result in CHECKED_URL:  
  61.                 return '[!] Url has checked!'  
  62.             else:  
  63.                 CHECKED_URL.append(result)  
  64.                 RESULT.append(url)  
  65.         return url  
  66.   
  67.   
  68.     def __is_connectable(self):  
  69.         print("进入__is_connectable()函数")  
  70.         #检验是否可以连接  
  71.         retry=3  
  72.         timeout=2  
  73.         for i in range(RETRY):  
  74.             try:  
  75.                 #print("进入_..............函数")  
  76.                 response=urllib2.urlopen(self.url,timeout=TIMEOUT)  
  77.                 return True  
  78.               
  79.             except:  
  80.                 if i==retry-1:  
  81.                     return False  
  82.   
  83.   
  84.     def get_next(self):  
  85.         #获取当前所有的url  
  86.         #print("进入get_next()函数")  
  87.         soup=BeautifulSoup(self.content)  
  88.         next_urls=soup.findAll('a')  
  89.         if len(next_urls)!=0:  
  90.             for link in next_urls:  
  91.                 self.handle_url(link.get('href'))  
  92.                 #print(link.text)  
  93.   
  94.   
  95.           
  96.     def run(self):  
  97.         #print("进入run()函数")  
  98.         if self.url:  
  99.             #print self.url  
  100.             if self.__is_connectable():  
  101.                 try:  
  102.                     self.content=urllib2.urlopen(self.url,timeout=TIMEOUT).read()  
  103.                     self.get_next()  
  104.   
  105.   
  106.                 except:  
  107.                     print('[!]Connect Failed')  
  108. #处理https开头的url的类和方法  
  109. class Poc:  
  110.     def run(self,url):  
  111.         global HOST  
  112.         global CHECKING_URL  
  113.         url=check_url(url)  
  114.   
  115.   
  116.         if not url.find('https'):  
  117.             HOST=url[:8]  
  118.         else:  
  119.             HOST=url[7:]  
  120.   
  121.   
  122.         for url in CHECKING_URL:  
  123.             print(url)  
  124.             url_node(url).run()  
  125.   
  126.   
  127. def check_url(url):  
  128.     url='http://'+url if not url.startswith('http') else url  
  129.     url=url[0:len(url)-1] if url.endswith('/') else url  
  130.   
  131.   
  132.     for i in range(RETRY):  
  133.         try:  
  134.             response=urllib2.urlopen(url,timeout=TIMEOUT)  
  135.             return url  
  136.         except:  
  137.             raise Exception("Connect error")  
  138.   
  139.   
  140. if __name__=='__main__':  
  141.     HOST='www.dataanswer.com'  
  142.     CHECKING_URL.append('http://www.dataanswer.com/')  
  143.     f=open('36大数据','w')  
  144.     for url in CHECKING_URL:  
  145.         f.write(url+'\n')  
  146.         print(url)  
  147.         url_node(url).run()  
  148.     print RESULT  
  149.     print "URL num:"+str(len(RESULT))  
  150.     print("time:%d s") % (time.time()-t)      
八,多线程
#对列和线程的结合
[html] view plain copy
 
  1. #!/usr/bin/env python  
  2. # -*- coding:utf-8 -*-  
  3. """  
  4. 一个简单的Python爬虫, 使用了多线程,   
  5. 爬取豆瓣Top前250的所有电影  
  6. """  
  7.   
  8. import urllib2, re, string  
  9. import threading, Queue, time  
  10. import sys  
  11.   
  12. reload(sys)  
  13. sys.setdefaultencoding('utf8')  
  14. _DATA = []  
  15. FILE_LOCK = threading.Lock()  
  16. SHARE_Q = Queue.Queue()  #构造一个不限制大小的的队列  
  17. _WORKER_THREAD_NUM = 3  #设置线程的个数  
  18.   
  19.   
  20. class MyThread(threading.Thread) :  
  21.   
  22.   
  23.     def __init__(self, func) :  
  24.         super(MyThread, self).__init__()  #调用父类的构造函数  
  25.         self.func = func  #传入线程函数逻辑  
  26.   
  27.   
  28.     def run(self) :  
  29.         self.func()  
  30.   
  31.   
  32. def worker() :  
  33.     global SHARE_Q  
  34.     while not SHARE_Q.empty():  
  35.         url = SHARE_Q.get() #获得任务  
  36.         my_page = get_page(url)  
  37.         find_title(my_page)  #获得当前页面的电影名  
  38.         #write_into_file(temp_data)  
  39.         time.sleep(1)  
  40.         SHARE_Q.task_done()  
  41.   
  42.   
  43. def get_page(url) :  
  44.     """  
  45.     根据所给的url爬取网页HTML  
  46.     Args:   
  47.         url: 表示当前要爬取页面的url  
  48.     Returns:  
  49.         返回抓取到整个页面的HTML(unicode编码)  
  50.     Raises:  
  51.         URLError:url引发的异常  
  52.     """  
  53.     try :  
  54.         my_page = urllib2.urlopen(url).read().decode("utf-8")  
  55.     except urllib2.URLError, e :  
  56.         if hasattr(e, "code"):  
  57.             print "The server couldn't fulfill the request."  
  58.             print "Error code: %s" % e.code  
  59.         elif hasattr(e, "reason"):  
  60.             print "We failed to reach a server. Please check your url and read the Reason"  
  61.             print "Reason: %s" % e.reason  
  62.     return my_page  
  63.   
  64.   
  65. def find_title(my_page) :  
  66.     """  
  67.     通过返回的整个网页HTML, 正则匹配前100的电影名称  
  68.     Args:  
  69.         my_page: 传入页面的HTML文本用于正则匹配  
  70.     """  
  71.     temp_data = []  
  72.     movie_items = re.findall(r'<span.*?class="title">(.*?)</span>', my_page, re.S)  
  73.     for index, item in enumerate(movie_items) :  
  74.         if item.find(" ") == -1 :  
  75.             #print item,  
  76.             temp_data.append(item)  
  77.     _DATA.append(temp_data)  
  78.   
  79. def main() :  
  80.     global SHARE_Q  
  81.     threads = []  
  82.     douban_url = "http://movie.douban.com/top250?start={page}&filter=&type="  
  83.     #向队列中放入任务, 真正使用时, 应该设置为可持续的放入任务  
  84.     for index in xrange(10) :     
  85.         SHARE_Q.put(douban_url.format(page = index * 25))  
  86.     for i in xrange(_WORKER_THREAD_NUM) :  
  87.         thread = MyThread(worker)  
  88.         thread.start()  #线程开始处理任务  
  89.     print("第%s个线程开始工作") % i  
  90.         threads.append(thread)  
  91.     for thread in threads :  
  92.         thread.join()  
  93.     SHARE_Q.join()  
  94.     with open("movie.txt", "w+") as my_file :  
  95.         for page in _DATA :  
  96.             for movie_name in page:  
  97.                 my_file.write(movie_name + "\n")  
  98.     print "Spider Successful!!!"  
  99.   
  100.   
  101. if __name__ == '__main__':  
  102.     main()  
九,爬虫框架Scrapy

items.py:用来定义需要保存的变量,其中的变量用Field来定义,有点像python的字典
pipelines.py:用来将提取出来的Item进行处理,处理过程按自己需要进行定义
spiders:定义自己的爬虫


爬虫的类型也有好几种:
  1)spider:最基本的爬虫,其他的爬虫一般是继承了该最基本的爬虫类,提供访问url,返回response的功能,会默认调用parse方法
  2)CrawlSpider:继承spider的爬虫,实际使用比较多,设定rule规则进行网页的跟进与处理, 注意点:编写爬虫的规则的时候避免使用parse名,因为这会覆盖继承的spider的的方法parse造成错误。   其中比较重要的是对Rule的规则的编写,要对具体的网页的情况进行分析。
  3)XMLFeedSpider 与 CSVFeedSpider 

(1)打开命令行,执行:scrapy startproject tutorial(项目名称)
(2)scrapy.cfg是项目的配置文件,用户自己写的spider要放在spiders目录下面
(3)解析:name属性很重要,不同spider不能使用相同的name
start_urls是spider抓取网页的起始点,可以包括多个url
parse方法是spider抓到一个网页以后默认调用的callback,避免使用这个名字来定义自己的方法。
当spider拿到url的内容以后,会调用parse方法,并且传递一个response参数给它,response包含了抓到的网页的内容,在parse方法里,你可以从抓到的网页里面解析数据。
(3)开始抓取,进入生成的项目根目录tutorial/,执行 scrapy crawl dmoz, dmoz是spider的name。
(4)保存对象:在items.py中添加一些类,这些类用来描述我们要保存的数据

from scrapy.item import Item, Field
class DmozItem(Item):
    title = Field()
    link = Field()
    desc = Field()
(5)执行scrapy crawl dmoz --set FEED_URI=items.json --set FEED_FORMAT=json后得到保存的文件
(6)让scrapy自动抓取网页上的所有链接

在parse方法里面提取我们需要的链接,然后构造一些Request对象,并且把他们返回,scrapy会自动的去抓取这些链接

posted @ 2018-04-06 05:47  中国人醒来了  阅读(487)  评论(0编辑  收藏  举报