Python爬蟲筆記(一)——基礎知識簡單整理

菜到懷疑人生發表於2018-07-08

登陸時候的使用者名稱和密碼可以放在http的頭部也可以放在http的body部分。

 

HTTPS是否可以抓取

由於https運用的加密策略是公開的,所以即使網站使用https加密仍然可以獲得資料,但是類似於微信這樣的app,它自己實現了一套加密演算法,想要抓取資料就變得比較困難。

 

製作爬蟲時需要注意的HTTP欄位

HTTP請求頭部分欄位解釋:

accept:表明請求的資源型別

accept-charset:表示請求的資源的編碼方式

accept-encoding:表明傳送方可以支援的編碼方式,需要注意gzip,它表示的是壓縮,伺服器為了節省空間可能就會壓縮資源,如果我們的http頭部含有gzip,在爬蟲中要記得用gzip解碼。

connection:keep-alive:避免建立的TCP連線被關閉,當載入完所需要的全部資源後,會傳送一個頭部帶有connection:close的http報文關閉TCP連線,因為爬蟲不需要多次請求資料(例如載入網頁時,獲得了html檔案後,還會請求獲得css、js等檔案),所以可以直接去掉,或者將值設定為close

cookie:一般的登陸策略是把登陸的資訊寫入cookie,伺服器把cookie返回給客戶端,客戶端每次請求資料都會帶上cookie,cookie中儲存的資料一般比較小

 

 

HTTP響應頭部分欄位解釋:

set—cookie:設定cookie

status:狀態碼,表明伺服器響應請求的狀態,狀態碼返回403,可能是需要登陸,或者是IP被封禁(如果是撥號上網(通過DHCP動態分配IP),一般等待十秒左右再次撥號即可分到不同的公網IP),狀態碼錶示重定向時,在urllib2會自動對重定向做處理,如果狀態碼為5xx,不一定就是伺服器當機,在分散式爬蟲中,如果爬取同一伺服器的不同網頁的多個爬蟲連續收到5XX,則可能是伺服器當機

 

爬取網頁的HTTP方法

網頁的靜態部分直接採用get方法即可獲得

網頁動態部分的ajax請求可能採用的get方法也可能採用post方法,可以使用web容器自動處理ajax

 

爬蟲爬取網頁的策略

爬蟲爬取頁面時,可以採用深度優先搜尋(採用棧)或是廣度優先搜尋(採用佇列)的策略(請檢視圖的遍歷方式),不斷爬取外連結,要注意外連結是否被訪問過,可以採用BoomFilter

 

記錄抓取過的網頁的策略

1、將其抓取過的URL儲存到資料庫中,將url設定為不允許重複的主鍵,每次都查詢資料庫中是否存在該URL來防止URL重複,由於資料庫是對磁碟進行操作,因此效率低下

2、將爬取過的url儲存在雜湊表中,雜湊表位於記憶體中,且雜湊表的查詢速度快,從而提高效率,由於一個URL可能比較長,為了節省記憶體,可以採用MD5(將任意長度的資料量轉換為一個固定長度的數字,通常是4個整型)等摘要演算法,對URL進行壓縮後儲存。在百度谷歌上可以通過輸入site:+域名來獲得網站url的個數,根據網站的大小來進行雜湊演算法和儲存資料結構的選擇,從而初步確定儲存url需要開闢的記憶體空間

 

簡單練習——用python實現的BFS爬取豆瓣電影首頁超連結

from urllib import request
from collections import deque
from pybloom_live import BloomFilter
from lxml import etree
import hashlib

class crawel_bfs:  
    request_header={
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
            'Accept-Encoding': 'br',
            'Accept-Language': 'zh-CN,zh;q=0.9',
            'Cache-Control': 'max-age=0',
            'Connection': 'keep-alive',
            'Cookie': 'bid=Kn9AT5duD7k; gr_user_id=32e433a7-19f0-4e17-80c4-56b58d7c0056; _vwo_uuid_v2=5985FEE132C29EC9C840D6C5EDD95323|67c2ccc8467fc02a9cce6928e86ea013; ll="118281"; __yadk_uid=I4Ki5RUaEWOUdpVIjJfRYo1MEuaW36hA; __utmv=30149280.16369; viewed="10483489_1115600_2230208_26857712_1569487_1623164_26708119_26677686"; __utma=30149280.965685249.1516632348.1528892392.1530880979.81; __utmc=30149280; __utmz=30149280.1530880979.81.57.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; __utmt=1; __utmb=30149280.1.10.1530880979; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1530880982%2C%22https%3A%2F%2Fwww.douban.com%2F%22%5D; _pk_ses.100001.4cf6=*; __utma=223695111.2038558801.1520348154.1528892435.1530880982.55; __utmb=223695111.0.10.1530880982; __utmc=223695111; __utmz=223695111.1530880982.55.51.utmcsr=douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/; _pk_id.100001.4cf6=da4243a2a9e242f1.1520348154.54.1530881042.1528892472.',
            'Host': 'movie.douban.com',
            'Referer': 'https://www.douban.com/',
            'Upgrade-Insecure-Requests': '1',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
            }
    
    cur_level=0
    max_level=2
        
    download_bf=BloomFilter(1024*1024,0.01)
    
    childque=deque()
    nowque=deque()
    
    def __init__(self,url,file_md5name,file_urlname):
        self.file_urlNameMd5_name=file_md5name
        self.file_urlName_name=file_urlname
        self.deal_file_md5=open(self.file_urlNameMd5_name,'r')
        self.file_md5=self.deal_file_md5.readlines()
        #用於輸入現有的檔案
        for url_md5_name in self.file_md5:
            #-1表示的是換行符,讀入時換行符不會佔據兩個字元
            self.download_bf.add(url_md5_name[:-1])
        self.deal_file_md5.close()
        self.file_md5=open(self.file_urlNameMd5_name,'a')     
        self.file_url=open(self.file_urlName_name,'a')
        self.nowque.append(url)
    
    def indeque(self,url):
        self.nowque.append(url)
        
    def outdeque(self):
        try:
            url=self.nowque.popleft()
            return url
        except Exception:
            self.cur_level+=1
            if self.cur_level==self.max_level:
                return None
            if len(self.childque)==0:
                return None
            self.nowque=self.childque
            self.childque=deque()
            return self.nowque.popleft()
        
    def crawler(self,url):
          try:
            #建立一個request物件,封裝一個報文物件
            req=request.Request(url,headers=self.request_header)
            #傳送報文
            response=request.urlopen(req)
            html_page=response.read()
            #按照固定編碼解碼
            html=etree.HTML(html_page.lower().decode('utf-8'))
            url_list=html.xpath('//a/@href')
            for url in url_list:
                if url.find('javascript:')!=-1:
                    continue
                if url.startswith('http://') is False:
                    if url.startswith('/') is True:
                        url='http://movie.douban.com'+url
                    else:
                        continue
                if url[-1]=='/':
                    url=url[:-1]
                temp=hashlib.md5(url.encode('utf-8')).hexdigest()
                if temp not in self.download_bf:
                    self.download_bf.add(url)
                    self.childque.append(url)
                    self.file_md5.write(temp+'\n')
                    self.file_url.write(url+'\n')
          except Exception:
            print("出現異常")
        
    def startcrawler(self):
        while True:
            url=self.outdeque()
            if url!=None:
                print("現在爬取"+url+"的超連結")
                self.crawler(url)
            else:
                break
        self.file_md5.close()
        self.file_url.close()
        
crawel=crawel_bfs("https://movie.douban.com/",'urlmd5.txt',
                  'urlname.txt')
crawel.startcrawler()

由於是簡單練習,所以沒有過分在意反爬蟲策略

效果如下:

urlname.txt檔案

 

urlmd5.txt檔案

 

 

相關文章