爬蟲是什么
什么是互聯(lián)網(wǎng)抱慌?
互聯(lián)網(wǎng)是由網(wǎng)絡(luò)設(shè)備(網(wǎng)線,路由器泣栈,交換機(jī)卜高,防火墻等等)和一臺臺計(jì)算機(jī)連接而成,像一張網(wǎng)一樣南片。
互聯(lián)網(wǎng)建立的目的掺涛?
互聯(lián)網(wǎng)的核心價(jià)值在于數(shù)據(jù)的共享/傳遞。
數(shù)據(jù)是存放于一臺臺計(jì)算機(jī)上的疼进,而將計(jì)算機(jī)互聯(lián)到一起的目的就是為了能夠方便彼此之間的數(shù)據(jù)共享/傳遞薪缆,否則你只能拿U盤去別人的計(jì)算機(jī)上拷貝數(shù)據(jù)了。
什么是上網(wǎng)伞广?爬蟲要做的是什么拣帽?
所謂的上網(wǎng)就是由客戶端計(jì)算機(jī)發(fā)送請求給服務(wù)器,將服務(wù)器的數(shù)據(jù)下載到本地的過程嚼锄。
用戶獲取網(wǎng)絡(luò)數(shù)據(jù)的方式:瀏覽器提交請求->下載網(wǎng)頁代碼->解析/渲染成頁面
爬蟲獲取網(wǎng)絡(luò)數(shù)據(jù)的方式:模擬瀏覽器發(fā)送請求->提取有用活動(dòng)數(shù)據(jù)->保存到數(shù)據(jù)庫/文件中
區(qū)別:爬蟲程序只提取網(wǎng)頁代碼中對我們有用的數(shù)據(jù)诞外。
如果把互聯(lián)網(wǎng)比作一張大的蜘蛛網(wǎng),那一臺計(jì)算機(jī)上的數(shù)據(jù)便是蜘蛛網(wǎng)上的一個(gè)獵物灾票,而爬蟲程序就是一只小蜘蛛,沿著蜘蛛網(wǎng)抓取自己想要的獵物/數(shù)據(jù)茫虽。
爬蟲的定義:向網(wǎng)站發(fā)起請求刊苍,獲取資源后分析并提取有用數(shù)據(jù)的程序既们。
爬蟲的價(jià)值:互聯(lián)網(wǎng)中最有價(jià)值的便是數(shù)據(jù),比如天貓商城的商品信息正什,鏈家網(wǎng)的租房信息啥纸,雪球網(wǎng)的證券投資信息等等,這些數(shù)據(jù)都代表了各個(gè)行業(yè)的真金白銀婴氮,可以說斯棒,誰掌握了行業(yè)內(nèi)的第一手?jǐn)?shù)據(jù),誰就成了整個(gè)行業(yè)的主宰主经,如果把整個(gè)互聯(lián)網(wǎng)的數(shù)據(jù)比喻為一座寶藏荣暮,那我們的爬蟲課程就是來教大家如何來高效地挖掘這些寶藏,掌握了爬蟲技能罩驻,你就成了所有互聯(lián)網(wǎng)信息公司幕后的老板穗酥,換言之,它們都在免費(fèi)為你提供有價(jià)值的數(shù)據(jù)惠遏。
爬蟲的基本流程
發(fā)送請求->獲取響應(yīng)內(nèi)容->解析內(nèi)容->保存數(shù)據(jù)
1. 發(fā)送請求
使用http庫向目標(biāo)站點(diǎn)發(fā)起請求砾跃,即發(fā)送一個(gè)Request
Request包含:請求頭、請求體等
2. 獲取響應(yīng)內(nèi)容
如果服務(wù)器能正常響應(yīng)节吮,則會(huì)得到一個(gè)Response
Response包含:html抽高,json,圖片透绩,視頻等
3. 解析內(nèi)容
解析html數(shù)據(jù):正則表達(dá)式翘骂,第三方解析庫如Beautifulsoup,pyquery等
解析json數(shù)據(jù):json模塊
解析二進(jìn)制數(shù)據(jù):以b的方式寫入文件
4. 保存數(shù)據(jù)
數(shù)據(jù)庫/文件
請求與響應(yīng)
http協(xié)議:https://www.baidu.com/
Request:用戶將自己的信息通過瀏覽器(socket client)發(fā)送給服務(wù)器(socket server)
Response:服務(wù)器接收請求渺贤,分析用戶發(fā)來的請求信息雏胃,然后返回?cái)?shù)據(jù)(返回的數(shù)據(jù)中可能包含其他鏈接,如:圖片志鞍,js瞭亮,css等)
ps:瀏覽器在接收Response后,會(huì)解析其內(nèi)容來顯示給用戶固棚,而爬蟲程序在模擬瀏覽器發(fā)送請求然后接收Response后统翩,是要提取其中的有用數(shù)據(jù)。
Request
請求方式
常用的請求方式:GET此洲,POST
其他請求方式:HEAD厂汗,PUT,DELETE呜师,OPTHONS
post與get請求最終都會(huì)拼接成urlencode
形式:k1=xxx&k2=yyy&k3=zzz
post請求的參數(shù)放在請求體內(nèi)娶桦,可用瀏覽器查看,存放于form data內(nèi)
get請求的參數(shù)直接放在url后
請求url
url全稱統(tǒng)一資源定位符,如一個(gè)網(wǎng)頁文檔衷畦,一張圖片栗涂,一個(gè)視頻等都可以用url唯一來確定
https://www.baidu.com/s?wd=圖片
(其中的中文'圖片'會(huì)被編碼)
網(wǎng)頁的加載過程是:
加載一個(gè)網(wǎng)頁,通常都是先加載document文檔祈争,
在解析document文檔的時(shí)候斤程,遇到鏈接,則針對超鏈接發(fā)起下載圖片的請求
請求頭
Accept:text/html,application/xhtml+xml,application/xml;
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Cookie:logged_in=no; tz=Asia%2FShanghai
Host:github.com
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 10
User-agent:請求頭中如果沒有user-agent客戶端配置菩混,服務(wù)端可能將你當(dāng)做一個(gè)非法用戶
cookies:cookie用來保存登錄信息
referer:從哪里跳來的
一般做爬蟲都會(huì)加上請求頭
請求體
如果是get方式忿墅,請求體沒有內(nèi)容
如果是post方式,請求體是Form Data
commit:Sign in
utf8:?
authenticity_token:LETizAkcEpnwCEUA6duyincUjGxpfNrZknwOUUmTVBPJfKMDGTwR3g2XbOEn5Yg==
login:111
password:222
ps:
1沮峡、登錄窗口疚脐,文件上傳等,信息都會(huì)被附加到請求體內(nèi)
2帖烘、登錄亮曹,輸入錯(cuò)誤的用戶名密碼,然后提交秘症,就可以看到post照卦,正確登錄后頁面通常會(huì)跳轉(zhuǎn),無法捕捉到post
Response
#1乡摹、響應(yīng)狀態(tài)
200:代表成功
301:代表跳轉(zhuǎn)
404:文件不存在
403:權(quán)限
502:服務(wù)器錯(cuò)誤
#2役耕、Respone header
set-cookie:可能有多個(gè),是來告訴瀏覽器聪廉,把cookie保存下來
#3瞬痘、preview就是網(wǎng)頁源代碼
最主要的部分,包含了請求資源的內(nèi)容
如網(wǎng)頁html板熊,圖片
二進(jìn)制數(shù)據(jù)等
總結(jié)
#1框全、總結(jié)爬蟲流程:
爬取--->解析--->存儲(chǔ)
#2、爬蟲所需工具:
請求庫:requests,selenium
解析庫:正則干签,beautifulsoup津辩,pyquery
存儲(chǔ)庫:文件,MySQL容劳,Mongodb喘沿,Redis
#3、爬蟲常用框架:
scrapy
爬取薪叻罚花網(wǎng)視頻
import requests
import re
import time
import hashlib
def get_page(url):
print('GET %s' %url)
try:
response=requests.get(url)
if response.status_code == 200:
return response.content
except Exception:
pass
def parse_index(res):
obj=re.compile('class="items.*?<a href="(.*?)"',re.S)
detail_urls=obj.findall(res.decode('gbk'))
for detail_url in detail_urls:
if not detail_url.startswith('http'):
detail_url='http://www.xiaohuar.com'+detail_url
yield detail_url
def parse_detail(res):
obj=re.compile('id="media".*?src="(.*?)"',re.S)
res=obj.findall(res.decode('gbk'))
if len(res) > 0:
movie_url=res[0]
return movie_url
def save(movie_url):
response=requests.get(movie_url,stream=False)
if response.status_code == 200:
m=hashlib.md5()
m.update(('%s%s.mp4' %(movie_url,time.time())).encode('utf-8'))
filename=m.hexdigest()
with open(r'./movies/%s.mp4' %filename,'wb') as f:
f.write(response.content)
f.flush()
def main():
index_url='http://www.xiaohuar.com/list-3-{0}.html'
for i in range(5):
print('*'*50,i)
#爬取主頁面
index_page=get_page(index_url.format(i,))
#解析主頁面,拿到視頻所在的地址列表
detail_urls=parse_index(index_page)
#循環(huán)爬取視頻頁
for detail_url in detail_urls:
#爬取視頻頁
detail_page=get_page(detail_url)
#拿到視頻的url
movie_url=parse_detail(detail_page)
if movie_url:
#保存視頻
save(movie_url)
if __name__ == '__main__':
main()
并發(fā)爬取
from concurrent.futures import ThreadPoolExecutor
import queue
import requests
import re
import time
import hashlib
from threading import current_thread
p=ThreadPoolExecutor(50)
def get_page(url):
print('%s GET %s' %(current_thread().getName(),url))
try:
response=requests.get(url)
if response.status_code == 200:
return response.content
except Exception as e:
print(e)
def parse_index(res):
print('%s parse index ' %current_thread().getName())
res=res.result()
obj=re.compile('class="items.*?<a href="(.*?)"',re.S)
detail_urls=obj.findall(res.decode('gbk'))
for detail_url in detail_urls:
if not detail_url.startswith('http'):
detail_url='http://www.xiaohuar.com'+detail_url
p.submit(get_page,detail_url).add_done_callback(parse_detail)
def parse_detail(res):
print('%s parse detail ' %current_thread().getName())
res=res.result()
obj=re.compile('id="media".*?src="(.*?)"',re.S)
res=obj.findall(res.decode('gbk'))
if len(res) > 0:
movie_url=res[0]
print('MOVIE_URL: ',movie_url)
with open('db.txt','a') as f:
f.write('%s\n' %movie_url)
# save(movie_url)
p.submit(save,movie_url)
print('%s下載任務(wù)已經(jīng)提交' %movie_url)
def save(movie_url):
print('%s SAVE: %s' %(current_thread().getName(),movie_url))
try:
response=requests.get(movie_url,stream=False)
if response.status_code == 200:
m=hashlib.md5()
m.update(('%s%s.mp4' %(movie_url,time.time())).encode('utf-8'))
filename=m.hexdigest()
with open(r'./movies/%s.mp4' %filename,'wb') as f:
f.write(response.content)
f.flush()
except Exception as e:
print(e)
def main():
index_url='http://www.xiaohuar.com/list-3-{0}.html'
for i in range(5):
p.submit(get_page,index_url.format(i,)).add_done_callback(parse_index)
if __name__ == '__main__':
main()