1. 程式人生 > >最全Python爬蟲總結(轉載)

最全Python爬蟲總結(轉載)

其中 網頁 -i 變量 oba cati nod style 應該

[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. url=‘http://www.dataanswer.top/‘
  10. result=getPage(url)
  11. file_name=‘test.doc‘
  12. file_path=‘doc‘
  13. if os.path.exists(file_path) == False:
  14. os.makedirs(file_path)
  15. local=os.path.join(file_path,file_name)
  16. f = open(local,"w+")
  17. f.write(result)
  18. f.close()
  19. #coding=utf-8
  20. import urllib
  21. import urllib2
  22. import os
  23. def getPage(url):
  24. request = urllib2.Request(url)
  25. response = urllib2.urlopen(request)
  26. return response.read()
  27. url=‘http://www.dataanswer.top/‘ #把該地址改成圖片/文件/視頻/網頁的地址即可
  28. result=getPage(url)
  29. file_name=‘test.doc‘
  30. file_path=‘doc‘
  31. if os.path.exists(file_path) == False:
  32. os.makedirs(file_path)
  33. local=os.path.join(file_path,file_name)
  34. urllib.urlretrieve(local)
三,普通模擬登錄
[html] view plain copy
  1. import urllib
  2. import urllib2
  3. import cookielib
  4. filename = ‘cookie.txt‘
  5. #聲明一個MozillaCookieJar對象實例來保存cookie,之後寫入文件
  6. cookie = cookielib.MozillaCookieJar(filename)
  7. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
  8. postdata = urllib.urlencode({
  9. ‘name‘:‘春天裏‘,
  10. ‘pwd‘:‘1222222‘
  11. })
  12. #登錄的URL
  13. loginUrl = ‘http://www.dataanswer.top/LoginService?action=tologin‘
  14. #模擬登錄,並把cookie保存到變量
  15. result = opener.open(loginUrl,postdata)
  16. #保存cookie到cookie.txt中
  17. cookie.save(ignore_discard=True, ignore_expires=True)
  18. #利用cookie請求訪問另一個網址
  19. gradeUrl = ‘http://www.dataanswer.top/LoginService?action=myHome‘
  20. #請求訪問
  21. result = opener.open(gradeUrl)
  22. 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. from selenium import webdriver
  7. driver = webdriver.Firefox()
  8. driver.get(‘http://www.newsmth.net/nForum/#!article/Intern/206790‘)
  9. html=driver.page_source.encode(‘utf-8‘,‘ignore‘) #這個函數獲取頁面的html
  10. print(html)
  11. 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. t=time.time()
  11. #設置的暫停爬取條數
  12. N_STOP=10
  13. #存放已經爬取過的url
  14. CHECKED_URL=[]
  15. #存放待爬取的url
  16. CHECKING_URL=[]
  17. #存放連接失敗的url
  18. FAIL_URL=[]
  19. #存放不能連接的url
  20. ERROR_URL=[]
  21. #失敗後允許連接的次數
  22. RETRY=3
  23. #連接超時時間
  24. TIMEOUT=20
  25. class url_node:
  26. def __init__(self,url):
  27. """
  28. url節點初始化
  29. :param url:String 當前url
  30. """
  31. self.url=url
  32. self.content=‘‘
  33. def __is_connectable(self):
  34. """
  35. 檢驗url是否可以連接
  36. """
  37. #在允許連接次數下連接
  38. for i in range(RETRY):
  39. try:
  40. #打開url沒有報錯,則表示可連接
  41. response=urllib2.urlopen(self.url,timeout=TIMEOUT)
  42. return True
  43. except:
  44. #如果在嘗試允許連接次數下報錯,則不可連接
  45. if i==RETRY-1:
  46. return False
  47. def get_next(self):
  48. """
  49. 獲取爬取該頁中包含的其他所有的url
  50. """
  51. soup=BeautifulSoup(self.content)
  52. #******************在此處可以從網頁中解析你想要的內容************************************
  53. next_urls=soup.findAll(‘a‘)
  54. if len(next_urls)!=0:
  55. for link in next_urls:
  56. tmp_url=link.get(‘href‘)
  57. #如果url不在爬取過的列表中也不在待爬取列表中則把其放到待爬列表中(沒有確保該url有效)
  58. if tmp_url not in CHECKED_URL and tmp_url not in CHECKING_URL:
  59. CHECKING_URL.append(tmp_url)
  60. def run(self):
  61. if self.url:
  62. if self.__is_connectable():
  63. try:
  64. #獲取爬取頁面的所有內容
  65. self.content=urllib2.urlopen(self.url,timeout=TIMEOUT).read()
  66. #從該頁面中獲取url
  67. self.get_next()
  68. except:
  69. #把連接失敗的存放起來
  70. FAIL_URL.append(self.url)
  71. print(‘[!]Connect Failed‘)
  72. else:
  73. #把不能連接的存放起來
  74. ERROR_URL.append(self.url)
  75. else:
  76. print("所給的初始url有問題!")
  77. if __name__==‘__main__‘:
  78. #把初始的url放到待爬的列表中
  79. CHECKING_URL.append(‘http://www.36dsj.com/‘)
  80. #不斷的從待爬的列表中獲取url進行爬取
  81. ff=open("Mytest.txt",‘w‘)
  82. i=0
  83. for url in CHECKING_URL:
  84. #對該url進行爬取
  85. url_node(url).run()
  86. #存放已經爬取過的url
  87. CHECKED_URL.append(url)
  88. #刪除CHECKING_URL中已經爬取過的url
  89. CHECKING_URL.remove(url)
  90. i+=1
  91. if i==N_STOP:
  92. #打出停止時的url,下次可以把該url作為初始繼續
  93. print url
  94. print("爬取過的列表長度:%d") % len(CHECKED_URL)
  95. print("待爬取的列表長度:%d") % len(CHECKING_URL)
  96. print("連接失敗的列表長度:%d") % len(FAIL_URL)
  97. print("不能連接的列表長度:%d") % len(ERROR_URL)
  98. break
  99. ff.close()
  100. 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. t=time.time()
  10. HOST=‘‘
  11. CHECKED_URL=[]
  12. CHECKING_URL=[]
  13. RESULT=[]
  14. RETRY=3
  15. TIMEOUT=20
  16. class url_node:
  17. def __init__(self,url):
  18. """
  19. url節點初始化
  20. :param url:String 當前url
  21. """
  22. self.url=self.handle_url(url,is_next_url=False)
  23. self.next_url=[]
  24. self.content=‘‘
  25. def handle_url(self,url,is_next_url=True):
  26. """
  27. 將所有的url處理成標準形式
  28. """
  29. global CHECKED_URL
  30. global CHECKING_URL
  31. #去掉尾部的‘/’
  32. url=url[0:len(url)-1] if url.endswith(‘/‘) else url
  33. if url.find(HOST)==-1:
  34. if not url.startswith(‘http‘):
  35. url=‘http://‘+HOST+url if url.startswith(‘/‘) else ‘http://‘+HOST+‘/‘+url
  36. else:
  37. #如果含有http說明是外鏈,url的host不是當前的host,返回空
  38. return
  39. else:
  40. if not url.startswith(‘http‘):
  41. url=‘http://‘+url
  42. if is_next_url:
  43. #下一層url放入待檢測列表
  44. if url not in CHECKING_URL:
  45. CHECKING_URL.append(url)
  46. else:
  47. #對於當前需要檢測的url將參數都替換為1,然後加入規則表
  48. #參數相同類型不同的url只檢測一次
  49. rule=re.compile(r‘=.*?\&|=.*?$‘)
  50. result=re.sub(rule,‘=1&‘,url)
  51. if result in CHECKED_URL:
  52. return ‘[!] Url has checked!‘
  53. else:
  54. CHECKED_URL.append(result)
  55. RESULT.append(url)
  56. return url
  57. def __is_connectable(self):
  58. print("進入__is_connectable()函數")
  59. #檢驗是否可以連接
  60. retry=3
  61. timeout=2
  62. for i in range(RETRY):
  63. try:
  64. #print("進入_..............函數")
  65. response=urllib2.urlopen(self.url,timeout=TIMEOUT)
  66. return True
  67. except:
  68. if i==retry-1:
  69. return False
  70. def get_next(self):
  71. #獲取當前所有的url
  72. #print("進入get_next()函數")
  73. soup=BeautifulSoup(self.content)
  74. next_urls=soup.findAll(‘a‘)
  75. if len(next_urls)!=0:
  76. for link in next_urls:
  77. self.handle_url(link.get(‘href‘))
  78. #print(link.text)
  79. def run(self):
  80. #print("進入run()函數")
  81. if self.url:
  82. #print self.url
  83. if self.__is_connectable():
  84. try:
  85. self.content=urllib2.urlopen(self.url,timeout=TIMEOUT).read()
  86. self.get_next()
  87. except:
  88. print(‘[!]Connect Failed‘)
  89. #處理https開頭的url的類和方法
  90. class Poc:
  91. def run(self,url):
  92. global HOST
  93. global CHECKING_URL
  94. url=check_url(url)
  95. if not url.find(‘https‘):
  96. HOST=url[:8]
  97. else:
  98. HOST=url[7:]
  99. for url in CHECKING_URL:
  100. print(url)
  101. url_node(url).run()
  102. def check_url(url):
  103. url=‘http://‘+url if not url.startswith(‘http‘) else url
  104. url=url[0:len(url)-1] if url.endswith(‘/‘) else url
  105. for i in range(RETRY):
  106. try:
  107. response=urllib2.urlopen(url,timeout=TIMEOUT)
  108. return url
  109. except:
  110. raise Exception("Connect error")
  111. if __name__==‘__main__‘:
  112. HOST=‘www.dataanswer.com‘
  113. CHECKING_URL.append(‘http://www.dataanswer.com/‘)
  114. f=open(‘36大數據‘,‘w‘)
  115. for url in CHECKING_URL:
  116. f.write(url+‘\n‘)
  117. print(url)
  118. url_node(url).run()
  119. print RESULT
  120. print "URL num:"+str(len(RESULT))
  121. 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. import urllib2, re, string
  8. import threading, Queue, time
  9. import sys
  10. reload(sys)
  11. sys.setdefaultencoding(‘utf8‘)
  12. _DATA = []
  13. FILE_LOCK = threading.Lock()
  14. SHARE_Q = Queue.Queue() #構造一個不限制大小的的隊列
  15. _WORKER_THREAD_NUM = 3 #設置線程的個數
  16. class MyThread(threading.Thread) :
  17. def __init__(self, func) :
  18. super(MyThread, self).__init__() #調用父類的構造函數
  19. self.func = func #傳入線程函數邏輯
  20. def run(self) :
  21. self.func()
  22. def worker() :
  23. global SHARE_Q
  24. while not SHARE_Q.empty():
  25. url = SHARE_Q.get() #獲得任務
  26. my_page = get_page(url)
  27. find_title(my_page) #獲得當前頁面的電影名
  28. #write_into_file(temp_data)
  29. time.sleep(1)
  30. SHARE_Q.task_done()
  31. def get_page(url) :
  32. """
  33. 根據所給的url爬取網頁HTML
  34. Args:
  35. url: 表示當前要爬取頁面的url
  36. Returns:
  37. 返回抓取到整個頁面的HTML(unicode編碼)
  38. Raises:
  39. URLError:url引發的異常
  40. """
  41. try :
  42. my_page = urllib2.urlopen(url).read().decode("utf-8")
  43. except urllib2.URLError, e :
  44. if hasattr(e, "code"):
  45. print "The server couldn‘t fulfill the request."
  46. print "Error code: %s" % e.code
  47. elif hasattr(e, "reason"):
  48. print "We failed to reach a server. Please check your url and read the Reason"
  49. print "Reason: %s" % e.reason
  50. return my_page
  51. def find_title(my_page) :
  52. """
  53. 通過返回的整個網頁HTML, 正則匹配前100的電影名稱
  54. Args:
  55. my_page: 傳入頁面的HTML文本用於正則匹配
  56. """
  57. temp_data = []
  58. movie_items = re.findall(r‘<span.*?class="title">(.*?)</span>‘, my_page, re.S)
  59. for index, item in enumerate(movie_items) :
  60. if item.find(" ") == -1 :
  61. #print item,
  62. temp_data.append(item)
  63. _DATA.append(temp_data)
  64. def main() :
  65. global SHARE_Q
  66. threads = []
  67. douban_url = "http://movie.douban.com/top250?start={page}&filter=&type="
  68. #向隊列中放入任務, 真正使用時, 應該設置為可持續的放入任務
  69. for index in xrange(10) :
  70. SHARE_Q.put(douban_url.format(page = index * 25))
  71. for i in xrange(_WORKER_THREAD_NUM) :
  72. thread = MyThread(worker)
  73. thread.start() #線程開始處理任務
  74. print("第%s個線程開始工作") % i
  75. threads.append(thread)
  76. for thread in threads :
  77. thread.join()
  78. SHARE_Q.join()
  79. with open("movie.txt", "w+") as my_file :
  80. for page in _DATA :
  81. for movie_name in page:
  82. my_file.write(movie_name + "\n")
  83. print "Spider Successful!!!"
  84. if __name__ == ‘__main__‘:
  85. 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會自動的去抓取這些鏈接

最全Python爬蟲總結(轉載)