Hello,我是 Alex 007,爲啥是007呢?因爲叫 Alex 的人太多了,再加上每天007的生活,Alex 007就誕生了。
今天呢,主要是跟大家分享一下花了兩天整理的爬蟲面試題,歡迎三連哦。
一. Requests
模塊
1. 簡述爬蟲的概念
爬蟲,即網絡機器人,如果把互聯網理解爲一張巨大的蜘蛛網,那麼爬蟲就是在這張網上捕獵的蜘蛛,它會根據你給定的目標將資源保存下來,也就是持久化存儲。
這個過程其實就類似於我們瀏覽器上網,只不過將這個繁瑣的過程通過編寫程序模擬的形式,讓爬蟲去互聯網上抓取數據。
2. 爬蟲有幾種分類,使用場景是什麼?
通用爬蟲
:通用爬蟲是搜索引擎爬蟲的重要組成部分,主要是將互聯網上的網頁下載到本地,再對這些網頁做相關處理(提取關鍵字、去掉廣告),最後提供一個用戶檢索接口。
聚焦爬蟲
:聚焦爬蟲是根據指定的需求
在通用爬蟲抓取到的網絡上提取目標數據。
增量式爬蟲
:增量式爬蟲是用來檢測網站數據更新的情況,且可以將網站更新的
數據進行爬取。
3. 簡述robots
協議的概念與作用
robots
協議是一種存放於網站根目錄下的ASCII
編碼的文本文件,它通常告訴網絡蜘蛛,此網站中的哪些內容是不應被搜索引擎的漫遊器獲取的,哪些是可以被漫遊器獲取的。
因爲一些系統中的URL
是大小寫敏感的,所以robots.txt
的文件名應統一爲小寫。
如果想單獨定義搜索引擎的漫遊器訪問子目錄時的行爲,那麼可以將自定的設置合併到根目錄下的robots.txt
,或者使用robots
元數據(Metadata
,又稱元數據)。
當一個搜索蜘蛛訪問一個站點時,它會首先檢查該站點根目錄下是否存在robots.txt,如果存在,搜索機器人就會按照該文件中的內容來確定訪問的範圍;如果該文件不存在,所有的搜索蜘蛛將能夠訪問網站上所有沒有被口令保護的頁面。
如果將網站視爲酒店裏的一個房間,robots.txt就是主人在房間門口懸掛的“請勿打擾”或“歡迎打掃”的提示牌。這個文件告訴來訪的搜索引擎哪些房間可以進入和參觀,哪些房間因爲存放貴重物品,或可能涉及住戶及訪客的隱私而不對搜索引擎開放。
但robots.txt是一個協議,而不是一個命令,也不是防火牆,如同守門人無法阻止竊賊等惡意闖入者。
4. 什麼是反爬機制和反反爬機制
反爬機制
:門戶網站通過相應的策略和技術手段,防止爬蟲程序進行網站數據的爬取。
1. U-A 校驗
2. 限制訪問頻率
3. 驗證碼
4. 登錄驗證
反反爬機制
:爬蟲程序通過相應的策略和技術手段,破解門戶網站的反爬蟲手段,從而爬取到相應的數據。
5. 簡述使用requests
模塊進行數據爬取的大致流程
(1)指定url
(2)基於requests
模塊發起請求
(3)獲取響應對象中的數據
(4)數據解析
(5)持久化存儲
6. 簡述使用requests
模塊爬取ajax
加載數據爬取的大致流程
(1)指定動態加載數據的url
(2)基於requests
模塊發起請求
(3)獲取響應對象中的數據
(4)數據解析
(5)持久化存儲
7. 簡述User-Agent
參數的作用
User Agent
中文名爲用戶代理,是Http
協議中的一部分,屬於請求頭的組成部分,User Agent
也簡稱UA
。
User Agent
向訪問網站提供發起請求的瀏覽器類型及版本、操作系統及版本、瀏覽器內核、等信息的標識。
通過這個標識,用戶所訪問的網站可以顯示不同的排版從而爲用戶提供更好的體驗或者進行信息統計。
在使用爬蟲獲取數據的時候,主要是想要獲取網站的數據,而有些網站則是不想讓我們的爬蟲進行獲取,所以我們會對爬蟲進行各種各樣的僞裝,UA
僞裝就是其中一種收單,讓對方識別我們爲爬蟲的概率更小,這樣爬取到想要的數據的概率就越大。
8. 在requests
模塊中接觸過哪些反爬機制
(1)驗證碼
爬蟲採集器優化方案:使用打碼平臺識別驗證碼。
(2)限制IP
訪問頻率
分析:沒有哪個正常人可以在一秒鐘內能訪問相同網站數十次次,除非是程序訪問,也就是搜索引擎爬蟲和爬蟲採集器。
弊端:一刀切,這同樣會阻止搜索引擎對網站的收錄
適用網站:不太依靠搜索引擎的網站
爬蟲採集器優化方案:減少單位時間的訪問次數,減低採集效率
(3)UA
校驗
分析:服務器端通過檢驗請求的User-Agent
來判斷是瀏覽器還是爬蟲程序。
爬蟲採集器優化方案:製作UA
僞裝
(4)登錄校驗
分析:搜索引擎爬蟲不會對每個需要登錄的網站設計登錄程序,但爬蟲採集器可以針對某個網站設計模擬用戶登錄提交表單行爲。
適用網站:極度討厭搜索引擎,且想阻止大部分採集器的網站
爬蟲採集器優化方案:製作擬用戶登錄提交表單行爲的模塊
(5)動態加載頁面
分析:有一部分網站,需要爬取的數據是通過Ajax
請求得到的,根據不同的情況動態加載數據。
爬蟲採集器優化方案:基於Selenium
+PhantomJS
模擬瀏覽器請求。
(6)數據加密
對部分數據進行加密的,可以使用selenium
進行截圖,使用python
自帶的pytesseract
庫進行識別,但是比較慢,最直接的方法是找到加密的方法進行逆向推理。
9. 介紹下requests
模塊中get
和post
方法常用參數的作用
GET:
# 封裝get請求參數
prams = {
'query':word,
'ie':'utf-8'
}
# 定製請求頭信息,相關的頭信息必須封裝在字典結構中
headers = {
# 定製請求頭中的User-Agent參數,當然也可以定製請求頭中其他的參數
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36',
}
response = requests.get(url=url,headers=headers,params=param)
POST:
# 定製post請求攜帶的參數(從抓包工具中獲取)
data = {
'cname':'',
'pid':'',
'keyword':'北京',
'pageIndex': '1',
'pageSize': '10'
}
# 定製請求頭信息,相關的頭信息必須封裝在字典結構中
headers = {
# 定製請求頭中的User-Agent參數,當然也可以定製請求頭中其他的參數
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36',
}
# 發起post請求,獲取響應對象
response = requests.get(url=url,headers=headers,data=data)
10. 簡述session
的創建流程及其該對象的作用
# 創建一個session對象,該對象會自動將請求中的cookie進行存儲和攜帶
session = requests.session()
# cookie由服務器創建並交給客戶端瀏覽器保存,會話跟蹤技術,再次訪問時,服務器就可以區分客戶端瀏覽器
# 使用session發送請求,目的是爲了將session保存該次請求中的cookie
session.post(url=post_url,data=formdata,headers=headers)
get_url = 'http://www.renren.com/960481378/profile'
# 再次使用session進行請求的發送,該次請求中已經攜帶了cookie
response = session.get(url=get_url,headers=headers)
11. 簡述如何使用requests
模塊進行模擬登錄,並抓取登錄成功後的某個二級頁面數據。
結合session = requests.post.session()
,先登陸成功
在瀏覽器獲取post
請求的參數response = requests.post(url=url,data=data,headers=headers)
然後獲取個人頁面url
,params = {}
,獲取get
請求參數response = requests.get(url=url,params=params,headers=headers)
。
最後獲取響應對象的頁面數據page_text = response.text
。
12. 簡述如何使用requests
模塊設置代理IP
1、在使用requests
模塊–get post —proxy
#不同的代理IP
proxy_list = [
{"http": "112.115.57.20:3128"},
{'http': '121.41.171.223:3128'}
]
# 隨機獲取UA和代理IP
header = random.choice(header_list)
proxy = random.choice(proxy_list)
# 設置代理
response = requests.get(url=url,headers=header,proxies=proxy)
2、在scrapy
框架下使用下載中間件
1.在下載中間件中攔截請求
2.將攔截到的請求的IP修改成某一代理IP
3.在配置文件(settings.py)中開啓下載中間件
二. 數據解析
1. 簡述使用在使用正則進行解析時用到的re.S
和re.M
的作用和區別
re.I
: 忽略大小寫
re.M
:多行匹配
re.S
:單行匹配
2. 簡述如何使用xpath
進行數據解析
(1)一般情況下
- 導入:
from lxml import etree
- 實例化一個
etree
對象並將瀏覽器網頁數據註冊到對象中,本地數據使用etree.parse
,網絡數據使用etree.HTML
- 編寫
xpath
表達式
(2)Scrapy
框架中response
對象已經封裝好了xpath
方法
3. 簡述如何使用bs4
進行數據解析
bs4
裏面有一個類BeautifulSoup
,通過這個類將網頁html
格式字符串實例化一個對象,然後通過對象的方法來進行查找指定元素。
將本地html
文件轉化爲對象:
soup = BeautifulSoup(open('soup.html', encoding='utf8'), 'lxml')
**根據標籤名查找:**只能查找得到第一個符合要求的節點,是一個bs4
自己封裝類的對象
soup.a
獲取屬性
soup.a.attrs
獲取得到所有屬性和值,是一個字典
soup.a.attrs['href']
獲取指定的屬性值
soup.a['href']
簡寫形式
獲取文本:
soup.a.string
soup.a.text
soup.a.get_text()
如果標籤裏面還有標籤,那麼string獲取就是空,而後兩個獲取的是純文本內容。
find_all方法
返回的是一個列表,列表裏面都是節點對象。
soup.find_all('a')
找到所有a
soup.find_all('a', limit=2)
提取符合要求的前兩個a
soup.find_all(['a', 'li'])
查找得到所有的a和li
soup.find_all('a', class_='xxx')
查找得到所有class是xxx的a
soup.find_all('li', class_=re.compile(r'^xiao'))
查找所有的class以xiao開頭的li標籤
select方法
id選擇器 #dudu
類選擇器 .xixi
標籤選擇器 div a h1
4. xpath
方法返回值類型是什麼
xpath函數返回的總是一個列表----列表裏面是選擇器對象。
可以用索引、和切片進行處理。
5. 在xpath
中如何/text()
和//text()
的區別是什麼
(1)/text()
表示獲取某個標籤下的文本內容
(2)//text()
表示獲取某個標籤下的文本內容和所有子標籤下的文本內容
6. id爲su的div標籤有一個子標籤ul,ul下有十個li標籤,每一個li標籤下都有一個a標籤,如何編寫xpath表達式可以解析到a標籤的href屬性值
li = response.xpath('//div[@id="su"]/ul/li')
for i in li:
i.xpath('./a/@href').extract_first()
7. class
爲wd
的div
標籤有一個子標籤ul
,ul
下有十個li
標籤,每一個li
標籤下都有一個a
標籤,如何編寫xpath
表達式可以解析到a
標籤中的文本內容
lis=response.xpath('//div[@class="wd"]/ul/li')
for li in lis:
a=li.xpath('./a/text()').extract_first()
8. 簡述extract()
和extract_first()
的區別
首先,只有在在Scrapy
中才有extract_first()
和extract()
,然後extract()
方法返回的是一個數組List
,裏面包含了多個string
,就算只有一個string
返回的也是列表的形式,而extract_first()
方法返回的是List
數組裏面的第一個string
字符串。
9. 簡述BeautifulSoup模塊中find和findall方法的區別
find
:找到第一個符合要求的標籤
find_all
:找到所有符合要求的標籤
10. 簡述BeautifulSoup模塊中select方法的使用
bs4
裏面有一個類BeautifulSoup
,通過這個類將網頁html
格式字符串實例化一個對象,然後通過對象的方法來進行查找指定元素。
select方法
id選擇器 #dudu
類選擇器 .xixi
標籤選擇器 div a h1
11. 簡述xpath插件的作用
就可以直接將xpath表達式作用到瀏覽器的網頁當中 ,進行驗證。
三. Scrapy 框架
1. 簡述scrapy
框架的安裝流程
pip install -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com twisted
pip install -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com pywin32
pip install -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com scrapy
-
twisted
Twisted 是用 Python 實現的基於事件驅動的網絡引擎框架,提供了允許阻塞行爲但不會阻塞代碼執行的方法,比較適合異步的程序。 -
pywin32
pywin32 主要的作用是方便 Python 開發者快速調用 Windows API的一個模塊庫。
1.1. 爲什麼要使用scrapy
框架?
首先,Scrapy
是基於twisted
的異步IO
框架,並且是純Python
實現的爬蟲框架,在性能方面有很大的優勢。
其次,在Scrapy
中可以加入requests
和BeautifulSoup
,內置的cssselector
和xpath
使用非常方便,還提供了很多其它的內置功能。
最後,Scrapy
是默認深度優先的,並且可以實現高併發的數據爬取,更加容易構建大規模的抓取項目。
2. scrapy
中持久化操作有幾種形式,分別如何實現?
(1)基於終端指令的持久化存儲
首先要保證parse
方法返回一個可迭代類型的對象,然後可以使用如下指令完成數據存儲的功能:
scrapy crawl baiDu -o baidu.json
(2)基於管道的持久化存儲
- 將爬蟲文件爬取到的數據封裝到
items
對象中 - 使用
yield
將items
對象提交給pipelines
管道持久化存儲 - 管道文件中的
process_item
方法接收並處理爬蟲文件提交過來的item
對象 - 配置文件
settings.py
中開啓管道
3. 簡述start_requests
方法的作用
源碼:
def start_requests(self):
for url in self.start_urls:
yield self.make_requests_from_url(url)
首先由start_requests
對start_urls
中的每一個url
發起請求(make_requests_from_url
),這個請求會被parse
接收。
4. 在scrapy
中如何進行post
請求發送
在scrapy
中可以通過scrapy.FormRequest
方法發送post
請求,參數爲formdata
:
yield scrapy.FormRequest(url=url,formdata=data,callback=self.parse)
5. 在scrapy
中如何手動進行一個get
請求的發送
在scrapy
中可以通過scrapy.Request
方法發送get
請求:
yield scrapy.Request(url=url,callback=self.parse)
6. 簡述管道文件的作用
在Scrapy
中,從每一個URL
中爬取的數據封裝成一個Response
對象,作爲參數返回給parse
方法或自定義的回調函數,parse
方法解析Response
爲item
,然後傳遞給管道,在pipelines.py
文件中提取item
中的內容,進行數據的持久化處理。
7. 簡述Request
方法中callback
參數的作用
爲當次request
方法指定回調函數,參數就是本次請求的返回結果。
8. 簡述Request
方法中meta
參數的作用
在Scrapy
中Request
方法的meta
參數要傳入一個字典,主要是傳遞數據用,meta
是隨着Request
產生時傳遞的嗎,比如meta = {‘key1’:value1}
,如果想要在下一個函數中取出value1
,只需要使用meta['key1']
即可。
9. 簡述下載中間件的作用
下載中間件是位於Scrapy
引擎和下載器之間的一層組件,用於處理請求,可以對請求設置隨機的User-Agent
,設置隨機的代理IP
,目的就在於防止應對網站的反爬策略。
下載器完成下載任務之後,在將Response
傳遞給引擎之前,下載中間件可以對Response
進行一系列處理,比如進行解壓等操作。
下載中間件需要註冊才能使用,在settings.py
文件中設置DOWNLOADER_MIDDLEWARES
,設置爲一個字典,鍵爲中間件類的路徑,值爲其中間件的順序。
9.1. 簡述蜘蛛中間件的作用
蜘蛛中間件是介於Scrapy
的Engine
和Spider
之間的鉤子框架,主要工作是處理蜘蛛的響應輸入和請求輸出。
9.2. 簡述調度中間件的作用
Scheduler Middlewares
是介於Scrapy
的Engine
和Scheduler
之間我的中間件,主要工作是處理從Scrapy
的Engine
發送到Scheduler
的請求和響應。
10. 簡述如何設置scrapy
項目的代理IP
(1)找一些代理IP
添加到settings.py
中
(2)在middlewares.py
中添加代理中間件:
class ProxyMiddleware(object):
def __init__(self, ip):
self.ip = ip
@classmethod
def from_crawler(cls, crawler):
return cls(ip=crawler.settings.get('PROXIES'))
def process_request(self, request, spider):
ip = random.choice(self.ip)
request.meta['proxy'] = ip
(3)在settings.py
中註冊代理IP
中間件
11. 簡述CrawlSpider
中鏈接提取器的作用
link = LinkExtractor(allow=r'/all/hot/recent/\d+')
Step 1. 實例化一個鏈接提取器對象
Step 2. 從起始url
響應頁面中按照正則表達式提取指定url
Step 3. 將鏈接提取器註冊給規則解析器
12. 簡述CrawlSpider
中規則解析器的作用
Step 1. 實例化一個規則提取器對象
Step 2. 規則解析器接收鏈接提取器發送的鏈接並對這些鏈接發起請求
Step 3. 根據指定的規則對返回頁面內容指定解析規則callback
,通過follow
確定是否遞歸獲取鏈接
Rule(link, callback='parse_item', follow=False),
13. 簡述scrapy
核心組件的工作原理
-
Spiders
爬蟲
爬蟲就是幹活的,編寫業務邏輯代碼,從特定的網頁中提取自己需要的信息,每個Spider
負責處理一個(些)特定網站。 -
Scrapy Engine
引擎
引擎用於處理整個Scrapy
系統的數據流,觸發事務等,是整個框架的核心。 -
Scheduler
調度器
調度器用來接收引擎發過來的請求並將其壓入隊列中,需要時彈出,可以簡單理解爲url
調度器,可以去除重複的url
。 -
Downloader
下載器
下載器顧名思義就是用於下載網頁並將內容返回給Spiders
,Scrapy
的下載器是建立在Twisted
高效異步模型上的。 -
Item、Pipeline
管道
管道負責處理Spiders
從網頁中抽取的實體並做持久化處理,同時可以驗證實體的有效性、清楚無用信息。
Scrapy
運行流程
-
引擎打開一個域名,蜘蛛處理這個域名,並讓蜘蛛獲取第一個爬取的
URL
。 -
引擎從蜘蛛那獲取第一個需要爬取的
URL
,然後作爲請求在調度中進行調度。 -
引擎從調度那獲取接下來進行爬取的頁面。
-
調度將下一個爬取的
URL
返回給引擎,引擎將他們通過下載中間件發送到下載器。 -
當網頁被下載器下載完成以後,響應內容通過下載中間件被髮送到引擎。
-
引擎收到下載器的響應並將它通過蜘蛛中間件發送到蜘蛛進行處理。
-
蜘蛛處理響應並返回爬取到的項目,然後給引擎發送新的請求。
-
引擎將抓取到的內容發送到項目管道做持久化處理,並向調度發送新的請求。
-
系統重複第二步後面的操作,直到調度中沒有請求,然後斷開引擎與域之間的聯繫。
14. 原生scrapy
框架爲何不能實現分佈式
其一:因爲多臺機器上部署的scrapy會各自擁有各自的調度器,這樣就使得多臺機器無法分配start_urls列表中的url。(多臺機器無法共享同一個調度器)
其二:多臺機器爬取到的數據無法通過同一個管道對數據進行統一的數據持久出存儲。(多臺機器無法共享同一個管道)
15.0. 簡述一下什麼是分佈式
當項目需要計算的數據量非常大,任務又非常多,一臺機器搞不定或者效率非常低的時候,就需要多臺機器共同協作,最後將所有機器完成的任務彙總在一起,從而完成大量的任務。
比如分佈式爬蟲,就是將一個項目拷貝到多臺電腦上,將多臺主機組合起來共同完成一個爬取任務,這樣可以大大提高爬取的效率。
15. 簡述基於scrapy-redis
分佈式的流程
16. 簡述一下scrapy
中selenium
的使用
當Engine
將url
對應的請求提交給Downloader
之後,Downloader
對目標網頁進行下載,然後將下載到的頁面數據封裝成response
之後返回給Engine
,而Engine
再將response
轉交給Spider
。
Spider
接收到的response
對象中存儲的頁面數據是沒有動態加載的,如果想獲取動態加載的數據,則需要在Downloader Middlewares
中對Downloader
返回給Engine
的response
響應對象進行攔截,將其內部存儲的頁面數據替換成攜帶動態加載數據的內容。
替換的操作就需要用到selenium
來模擬瀏覽器了,在Scrapy
中使用selenium
的流程如下:
(1)重寫爬蟲的構造方法,在該方法中使用selenium
實例化一個瀏覽器對象;
(2)重寫爬蟲文件的close
方法,在其內部關閉瀏覽器對象,在爬蟲結束時被調用;
(3)重寫Downloader Middlewares
的process_response
方法,讓改方法對相應對象進行攔截和替換response
中存儲的頁面數據;
(4)在配置文件中開啓下載中間件。