一 基本流程:
#1、发起请求
使用http库向目标站点发起请求,即发送一个Request
Request包含:请求头、请求体等
#2、获取响应内容
如果服务器能正常响应,则会得到一个Response
Response包含:html,json,图片,视频等
#3、解析内容
解析html数据:正则表达式,第三方解析库如Beautifulsoup,pyquery等
解析json数据:json模块
解析二进制数据:以b的方式写入文件
#4、保存数据
数据库
文件
二 请求与响应
#http协议:http://www.cnblogs.com/linhaifeng/articles/8243379.html
#Request:用户将自己的信息通过浏览器(socket client)发送给服务器(socket server)
#Response:服务器接收请求,分析用户发来的请求信息,然后返回数据(返回的数据中可能包含其他链接,如:图片,js,css等)
#ps:浏览器在接收Response后,会解析其内容来显示给用户,而爬虫程序在模拟浏览器发送请求然后接收Response后,是要提取其中的有用数据。
三 Request
#1、请求方式:
常用的请求方式:GET,POST
其他请求方式:HEAD,PUT,DELETE,OPTHONS
ps:用浏览器演示get与post的区别,(用登录演示post)
post与get请求最终都会拼接成这种形式:k1=xxx&k2=yyy&k3=zzz
post请求的参数放在请求体内:
可用浏览器查看,存放于form data内
get请求的参数直接放在url后
#2、请求url
url全称统一资源定位符,如一个网页文档,一张图片
一个视频等都可以用url唯一来确定
url编码
https://www.baidu.com/s?wd=图片
图片会被编码(看示例代码)
网页的加载过程是:
加载一个网页,通常都是先加载document文档,
在解析document文档的时候,遇到链接,则针对超链接发起下载图片的请求
#3、请求头
User-agent:请求头中如果没有user-agent客户端配置,
服务端可能将你当做一个非法用户
host
cookies:cookie用来保存登录信息
一般做爬虫都会加上请求头
#4、请求体
如果是get方式,请求体没有内容
如果是post方式,请求体是format data
ps:
1、登录窗口,文件上传等,信息都会被附加到请求体内
2、登录,输入错误的用户名密码,然后提交,就可以看到post,正确登录后页面通常会跳转,无法捕捉到post
# urlencode是将在请求出现的查找关键字信息转为urlencode编码
from urllib.parse import urlencode
import requests
headers={
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Cookie':'H_WISE_SIDS=101556_115474_115442_114743_108373_100099_115725_106201_107320_115339_114797_115553_116093_115546_115625_115446_114329_115350_114275_116040_110085; PSTM=1494300712; BAIDUID=42FE2934E37AF7AD1FA31D8CC7006D45:FG=1; BIDUPSID=2996557DB2710279BD865C50F9A68615; MCITY=-%3A; __cfduid=da9f97dea6458ca26aa4278280752ebb01508939712; BDSFRCVID=PGLsJeCCxG3wt_3ZUrBLDfv2D_qBZSjAgcEe3J; H_BDCLCKID_SF=tJAOoCLytI03qn5zq4Oh-4oHhxoJq5QxbT7Z0l8KtfcNVJQs-lCMhbtp-l3GJPoLWK6hBKQmWIQHDnbsbq0M2tcQXR5-WROCte74KKJx-4PWeIJo5tKh04JbhUJiB5OLBan7Lq7xfDDbbDtmej_3-PC3ql6354Rj2C_X3b7EfKjIOtO_bfbT2MbyeqrNQlTkLIvXoITJQD_bEP3Fbfj2DPQ3KabZqjDjJbue_I05f-oqebT4btbMqRtthf5KeJ3KaKrKW5rJabC3hPJeKU6qLT5Xjh6B5qDfyDoAbKOt-IOjhb5hMpnx-p0njxQyaR3RL2Kj0p_EWpcxsCQqLUonDh8L3H7MJUntKjnRonTO5hvvhb6O3M7-XpOhDG0fJjtJJbksQJ5e24oqHP-kKPrV-4oH5MQy5toyHD7yWCvjWlT5OR5Jj6KMjMkb3xbz2fcpMIrjob8M5CQESInv3MA--fcLD2ch5-3eQgTI3fbIJJjWsq0x0-jle-bQypoa-U0j2COMahkMal7xO-QO05CaD53yDNDqtjn-5TIX_CjJbnA_Hn7zepoxebtpbt-qJJjzMerW_Mc8QUJBH4tR-T3keh-83xbnBT5KaKO2-RnPXbcWjt_lWh_bLf_kQN3TbxuO5bRiL66I0h6jDn3oyT3VXp0n54nTqjDHfRuDVItXf-L_qtDk-PnVeUP3DhbZKxtqtDKjXJ7X2fclHJ7z-R3IBPCD0tjk-6JnWncKaRcI3poiqKtmjJb6XJkl2HQ405OT-6-O0KJcbRodobAwhPJvyT8DXnO7-fRTfJuJ_DDMJDD3fP36q4QV-JIehmT22jnT32JeaJ5n0-nnhP3mBTbA3JDYX-Oh-jjRX56GhfO_0R3jsJKRy66jK4JKjHKet6vP; ispeed_lsm=0; H_PS_PSSID=1421_24558_21120_17001_24880_22072; BD_UPN=123253; H_PS_645EC=44be6I1wqYYVvyugm2gc3PK9PoSa26pxhzOVbeQrn2rRadHvKoI%2BCbN5K%2Bg; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598',
'Host':'www.baidu.com',
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'}
# response=requests.get('https://www.baidu.com/s?'+urlencode({'wd':'美女'}),headers=headers)
response=requests.get('https://www.baidu.com/s',params={'wd':'美女'},headers=headers) #params内部就是调用urlencode
print(response.text)
四 Response
#1、响应状态
200:代表成功
301:代表跳转
404:文件不存在
403:权限
502:服务器错误
#2、Respone header
set-cookie:可能有多个,是来告诉浏览器,把cookie保存下来
#3、preview就是网页源代码
最主要的部分,包含了请求资源的内容
如网页html,图片
二进制数据等
五 总结及爬取梨视屏网站
#1、总结爬虫流程:
爬取--->解析--->存储
#2、爬虫所需工具:
请求库:requests,selenium
解析库:正则,beautifulsoup,pyquery
存储库:文件,MySQL,Mongodb,Redis
#3、爬虫常用框架:
scrapy
# 1.爬取首页数据,解析获取视频的详情链接
# 2.遍历每一个详情链接,并访问
# 3.从详情页面解析得到需要的数据 (视频链接,标题,详情,时间,收藏次数)
import requests
import re
import os
from threading import Thread
from concurrent.futures import ThreadPoolExecutor
base_url = "https://www.pearvideo.com/"
def get_index():
res = requests.get(base_url,headers={
"user-agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
"referer": "https: // www.baidu.com / link?url = fUq54ztdrrLaIUXa - p6B9tuWXC3byFJCyBKuvuJ_qsPw8QLrWIfekFKGgmhqITyF & wd = & eqid = c5366da10000199a000000025c45768a"
})
return res.text
def parser_index(text):
urls = re.findall('<a href="(.*?)" class="vervideo-lilink actplay">',text)
urls = [base_url + i for i in urls]
# print(urls)
return urls
def get_details(url):
res = requests.get(url)
print(res.status_code)
return res.text
def parser_details(text):
# 视频的地址
video_url = re.search(r'srcUrl="(.*?.mp4)"',text).group(1)
# 标题
title = re.search('<h1 class="video-tt">(.*?)</h1>',text).group(1)
# 详情
content = re.search('<div class="summary">(.*?)</div>',text).group(1)
# 时间
date = re.search('<div class="date">(.*?)</div>', text).group(1)
# 点赞数量
count = re.search('<div class="fav" data-id=".*?">(.*?)</div>', text).group(1)
return {"video_url":video_url,"title":title,"content":content,"date":date,"count":count}
def download_video(url,title):
data = requests.get(url)
if not os.path.exists("videos"):
os.makedirs("videos")
filename = os.path.join("videos",title)+".mp4"
filename = filename.replace(":","_")
with open(filename,"wb") as f:
f.write(data.content)
print("%s download finished!" % title)
if __name__ == '__main__':
pool = ThreadPoolExecutor(5)
data = get_index()
urls = parser_index(data)
for i in urls:
t = get_details(i)
dic = parser_details(t)
# Thread(target=download_video,args=(dic["video_url"],dic["title"])).start()
pool.submit(download_video,dic["video_url"],dic["title"])
print("submit task",dic["title"])
print("submit finished")