未经允许,不可转载!!!如果文章内容有不恰当之处,还请指出!
本篇教程比较基础,适合写爬虫没思路、不知道内部机制的萌新看。文章内容可能有点乱,但全是干货!
注:虽然内容基础,但仍需要对python有一定的基础,纯萌新阅读此文可能会有一点吃力
编译工具及环境:
1.简单的说,网络爬虫就是电脑按照你所编写的代码对网络中资源进行处理,并根据你指定的方式进行保存或其他骚操作。类似于针对网络资源进行批处理
2.爬虫的合法性:这个就很难说了。不过我可以举个栗子,来比喻一下
图片来自网络
刀这种工具大家都知道,都用过,我们平常使用刀都是用来做饭,切东西、拆快递等。但有些亡命之徒用他来sha人,伤害其他人,这使我们知道刀也是一种危险的东西,但我们又不能离开这种工具,不能一拍子全打死,直接将刀禁用,毕竟我们又没违法,对吧。
而Python爬虫合法性也类似于这种概念-----违不违法不取决于这门技术内容,而是取决于使用者的行为
所以我们只要不干违法的事就可以了,其他的可以由我们任意发挥都无所谓。
*如果你比较了解可以直接跳过
我们平时在使用浏览器浏览东西时,请求和响应这两个环节可以说是最频繁触发的了,不过,其内容比较简单,可以参考看望病人或串亲戚的流程。
其实也没什么好说的
请求时我们的浏览器会发送请求,而请求中会带有一些信息,而这些信息有一个简单易懂的名字----“headers 头(请求头信息)”。
英语好的同学,可能已经发现一点点端倪了,这个header它加了个s
”唉?这是为什么啊,头为什么还可以是复数形式的?“
“因为他有多个头,是个怪物”
这是因为请求头信息有多条,并不是单单只有一条,这就好比你去串亲戚,总不能拿瓶饮料就去吧?(如果你连饮料都不拿,那你真是。。。)肯定要精心准备,多拿些东西,不然没牌face。
而请求头也是这样的,带着多种信息去请求服务器。
*headers是请求信息,且不唯一(也不一定为多个,具体信息数量由服务器决定),同时,这也是服务器检查是否为爬虫的关键
大体解释完了,接下来我们来实战!!!
#均使用pip工具,原因:一键式安装,快捷方便
下载Requests库,一切的基础
这里使用了清华的镜像,如果你已经设置过镜像,可以不加-i后缀
pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple
下载lxml库,解析库
后文会说明为什么下载此库,现在只做简单解释:为xpath使用做铺垫
pip install lxml -i https://pypi.tuna.tsinghua.edu.cn/simple
# -*- coding: utf-8 -*-
#名称:bilibili封面批量下载
#作者:漫游感知
#CSDN:https://blog.csdn.net/qq_45429426?spm=1001.2014.3001.5343
import requests
from lxml import etree #这里调用lxml库中的etree方法,来使用etree下的xpath方法
举例视频URL:https://www.bilibili.com/video/BV1Az4y1S7cY
图片URL:http://i0.hdslb.com/bfs/archive/e47632eba6c7d838ec999a9d74306c1225094465.jpg
方法 | 常用参数 |
---|---|
requests.get() | url=* , headers=* |
实例代码如下(B站貌似并未使用反爬,但为了保证正常,还是先修改了headers,修改方式如下代码。文章第5个部分专讲反爬及headers运用)
# -*- coding: utf-8 -*-
#名称:bilibili封面批量下载
#作者:漫游感知
#CSDN:https://blog.csdn.net/qq_45429426?spm=1001.2014.3001.5343
import requests #发送请求与接收响应数据
from lxml import etree #这里调用lxml中的etree类型为使用xpath铺垫
def bili(url):
"""
这里定义一个名为“bili”的函数,并要求传入一个数值----url
这个函数用于获取视频页面源码
"""
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
} #这里必须是字典格式(键值对形式)
url = str(url) #将传入信息转为字符串(保险)
resp = requests.get(url=url,headers=headers) #发送get请求,并使用自带头信息来进行反反爬
html_text = resp.text #将获取信息转为文本
if resp.status_code == 200: #如果状态码为200(请求成功)则返回网页数据
return html_text
else:
print('Get error')
url = 'https://www.bilibili.com/video/BV1Az4y1S7cY'
get_web = bili(url)
print(get_web)
假设我们需要让电脑取出五角星这个图形,那么我们应该怎么表达呢?
那是不是应该先告诉电脑,去html中(/html),取出head(/html/head),再取出第三个mate(/html/head/mate[3]),最后明确是第三个mate中的五角星(/html/head/mate[3]/@五角星)。
上述这一流程就是xpath语法编写的流程,其中/和@分别类似于路径符号和选择
'/html/head/meta[11]/@content' #下文会进行讲述
注意,在使用xpath前必须使用etree.HTML()对文本进行初处理,实例:
def bili_get_img(text):
"""
这里定义一个名为bili_get_img的函数,用来解析图片链接,即反馈为链接
同时要求传入一个文本,即bili函数反馈的网页源码
"""
text = str(text)
reap_xpath = etree.HTML(text) #初处理,并赋值给reap_xpath
方法 | 适用于 |
---|---|
etree.HTML() | requests库所获取的内容,即非本地文件 |
etree.parse() | 处理本地xml、html等文件,即本地支持文件 |
符号 | 意思 |
---|---|
/ | 选取此节点的所有子节点。即一层一层选择 |
// | 从根节点选取。即所有选择 |
@ | 选取有指定class的元素 |
代码实例:
def bili_get_img(text):
"""
这里定义一个名为bili_get_img的函数,用来解析图片链接,即反馈为链接
同时要求传入一个文本,即bili函数反馈的网页源码
"""
text = str(text)
reap_xpath = etree.HTML(text) #初处理,并赋值给reap_xpath
img_url = reap_xpath.xpath('/html/head/meta[11]/@content') #xpath语法,传入的是字符串,并将结果赋值给img_url
print(img_url) #打印结果
结果>>> ['http://i0.hdslb.com/bfs/archive/e47632eba6c7d838ec999a9d74306c1225094465.jpg']
转为字符串(加[0],有基础都知道)
def bili_get_img(text):
"""
这里定义一个名为bili_get_img的函数,用来解析图片链接,即反馈为链接
同时要求传入一个文本,即bili函数反馈的网页源码
"""
text = str(text)
reap_xpath = etree.HTML(text) #初处理,并赋值给reap_xpath
img_url = reap_xpath.xpath('/html/head/meta[11]/@content')[0] #xpath语法,传入的是字符串,必将结果赋值给img_url
print(img_url) #打印结果
结果>>> http://i0.hdslb.com/bfs/archive/e47632eba6c7d838ec999a9d74306c1225094465.jpg
随便写一个with…open就可以实现保存,这算是基础就不讲了,给个代码实例:
def download_img(url,path):
"""
定义下载函数
url参数:前面解析出的图片链接
path:让用户输入的保存路径
"""
url = str(url)
path = str(str(path) + str(url).split('/')[-1]) #避免因为链接中\\影响保存路径来引发报错
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
} #这里必须是字典格式(键值对形式)
file_img = requests.get(url=url,headers=headers) #这里使用头文件保证安全
with open(path,'wb') as file:
file.write(file_img.content)
file.close()
print('图片保存完毕')
批量爬取无非就是for…in循环
if __name__ == '__main__':
path = input('请输入保存路径')
with open('url_list.txt','r') as e_list:
list_url = e_list.read() #可以让用户把想要的视频封面所对的视频链接放在这个文件
for url in list_url:
url = url
get_web = bili(url) #调用前面编写的源码获取函数来获取源码
url_img = bili_get_img(get_web) #调用解析源码函数来获取图片链接
download_img(url_img, path) #保存图片
加一点细节处理
if __name__ == '__main__':
path = input('请输入保存路径:')
try:
with open('url_list.txt', 'r') as e_list:
list_url = e_list.read() # 可以让用户把想要的视频封面所对的视频链接放在这个文件
except FileNotFoundError:
#如果没有文件,则说明是头次运行,为保证正常使用可以加个try...except
with open('url_list.txt','w+') as file:
file.write(',,')
print('错误!现已创建一个名为url_list的文本文件,文件内容写入方式为:链接与链接之间请用英文逗号隔开!如:wwww.111.com,www.222.com')
exit()
for url in list_url.split(','):
url = url
if str(url) == '':
print('错误,文本中没有链接,或者有空余的链接位置!') #防止因为传入空信息而报错
else:
get_web = bili(url) # 调用前面编写的源码获取函数来获取源码
url_img = bili_get_img(get_web) # 调用解析源码函数来获取图片链接
download_img(url_img, path) # 保存图片
print('所有下载完成')
运行演示:
最终代码:
# -*- coding: utf-8 -*-
#名称:bilibili封面批量下载
#作者:漫游感知
#CSDN:https://blog.csdn.net/qq_45429426?spm=1001.2014.3001.5343
import requests #发送请求与接收响应数据
from lxml import etree #这里调用lxml中的etree类型为使用xpath铺垫
def bili(url):
"""
这里定义一个名为“bili”的函数,并要求传入一个数值----url
这个函数用于获取视频页面源码
"""
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
} #这里必须是字典格式(键值对形式)
url = str(url) #将传入信息转为字符串(保险)
resp = requests.get(url=url,headers=headers) #发送get请求,并使用自带头信息来进行反反爬
html_text = resp.text #将获取信息转为文本
if resp.status_code == 200: #如果状态码为200(请求成功)则返回网页数据
return html_text
else:
print('Get error')
def bili_get_img(text):
"""
这里定义一个名为bili_get_img的函数,用来解析图片链接,即反馈为链接
同时要求传入一个文本,即bili函数反馈的网页源码
"""
text = str(text)
reap_xpath = etree.HTML(text) #初处理,并赋值给reap_xpath
img_url = reap_xpath.xpath('/html/head/meta[11]/@content')[0] #xpath语法,传入的是字符串,必将结果赋值给img_url
print(img_url) #打印结果
return img_url
def download_img(url,path):
"""
定义下载函数
url参数:前面解析出的图片链接
path:让用户输入的保存路径
"""
url = str(url)
path = str(str(path) + str(url).split('/')[-1]) #避免因为链接中\\影响保存路径来引发报错
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
} #这里必须是字典格式(键值对形式)
file_img = requests.get(url=url,headers=headers) #这里使用头文件保证安全
with open(path,'wb') as file:
file.write(file_img.content)
file.close()
print('图片保存完毕')
if __name__ == '__main__':
path = input('请输入保存路径:')
try:
with open('url_list.txt', 'r') as e_list:
list_url = e_list.read() # 可以让用户把想要的视频封面所对的视频链接放在这个文件
except FileNotFoundError:
with open('url_list.txt','w+') as file:
file.write(',,')
print('错误!现已创建一个名为url_list的文本文件,文件内容写入方式为:链接与链接之间请用英文逗号隔开!如:wwww.111.com,www.222.com')
input('请重新运行程序!按任意键退出本次运行')
for url in list_url.split(','):
url = url
if str(url) == '':
print('错误,文本中没有链接,或者有空余的链接位置!') #防止因为传入空信息而报错
else:
get_web = bili(url) # 调用前面编写的源码获取函数来获取源码
url_img = bili_get_img(get_web) # 调用解析源码函数来获取图片链接
download_img(url_img, path) # 保存图片
print('所有下载完成')
PS:这里找一个会出现乱码问题及有反爬机制的网站,下面是所找的网站链接:
https://www.qidian.com/
import requests
url = 'https://www.qidian.com/'
resp = requests.get(url=url) #直接向网站方式请求
print(resp.text)
结果>>>
g_data.staticPath = '//qidian.gtimg.com/qd';</script><script data-ignore="true" id="LBFnode" src="//qidian.gtimg.com/lbf/1.1.0/LBF.js?max_age=31536000"></script><script>// LBF é
ç½®
LBF.config({
"paths":{
"site":"//qidian.gtimg.com/qd/js","qd":"//qidian.gtimg.com/qd","common":"//qidian.gtimg.com/common/1.0.0"},"vars":{
"theme":"//qidian.gtimg.com/qd/css"},"combo":true,"debug":false});
LBF.use(['lib.jQuery'], function ($) {
window.$ = $;
});</script><script>LBF.use(['monitor.SpeedReport', 'qd/js/component/login.a4de6.js', 'qd/js/index/index.3fe03.js' ], function (SpeedReport, Login, Index) {
// 页é¢é€»è¾‘å
¥å£
if(Login){
Login.init().always(function(){
Index && typeof Index === 'function' && new Index();
})
}
if(219 && 219 != ''){
$(window).on('load.speedReport', function () {
// speedTimer[onload]
speedTimer.push(new Date().getTime());
var f1 = 7718, // china reading limited's ID
f2 = 219, // site ID
f3 = 4; // page ID
// chrome & IE9 Performance API
SpeedReport.reportPerformance({
flag1: f1,
flag2: f2,
flag3IE: f3,
flag3Chrome: f3,
。。。。。。。。省略。。。。。。。。。。
啊这,很明显不一样,从前几行上看就不一样
引出问题:
用浏览器访问发现网站是正常的,这说明不是网站的问题,而是我们的请求有问题,被拒绝连接了。
这时,我们应有疑惑,为什么我们的请求会被拒绝?为什么浏览器就可以正常请求呢?
分析:
– 1.被拒绝,说明网站有反爬机制,我们携带的请求信息被网站视为爬虫了,即我们的伪装不到位
– 2.那我们请求时都带什么数据去请求了?即我们的请求头是什么?
– 3.既然我们的请求头不行,那为什么浏览器发送的请求头可以?即浏览器的请求头是什么?
– 4.如果我们用浏览器的请求头去请求网站是不是也可以请求成功了?即使用浏览器的请求头
一通分析下来,目标就很明确了
目标:把自己的头信息全部改为浏览器的头信息
import requests
url = 'https://www.qidian.com/'
resp = requests.get(url=url)
# print(resp.text)
print(resp.requests.headers) #查看请求时使用的头信息
结果>>>
{
'User-Agent': 'python-requests/2.25.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
看到反馈值中的一个字样,我们就应该明白了
这个字样就是“python”
好家伙,上来就自报家门,大声告诉服务器:“我是个爬虫,想要爬取信息”,这不拒绝你拒绝谁啊?!
在我们修改前,我们先学会如何使用浏览器的调试工具来获取浏览器头信息
复制后,我们来到我们的编译器,创建个字典,并将刚才复制的信息以键值对形式粘贴到字典中
并在requests.get()中加入一个参数,完成我们的修改头信息
结果>>>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
/>
<title>é˜
æ–‡æ¸ é“广告投放平å°</title>
<meta name="keywords" content="红袖读书" />
<meta name="description" content="红袖读书" />
<meta name="robots" content="all" />
<meta name="googlebot" content="all" />
<meta name="baiduspider" content="all" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
<meta name="renderer" content="webkit" />
<meta name="publicPath" content />
<script>
(function (i, s, o, g, r, a, m) {
i["QDAnalyticsObject"] = r;
(i[r] =
i[r] ||
function () {
(i[r].q = i[r].q || []).push(arguments);
}),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(
window,
document,
"script",
"https://noah2-1252317822.file.myqcloud.com/npm/@noah-common/yep@latest/dist/yep.js",
"yep"
);
yep("set", {
rate: 0.8, appid: 10042 });
</script>
<link rel="stylesheet" href="/static/css/ad40750e846edc80a8ac.css" />
<script>
window.routerBase = "/";
</script>
<script>
//! umi version: 3.2.22
</script>
</head>
<body>
<div id="root">
<div
style="
position: absolute;
top: 50%;
left: 0;
width: 100%;
text-align: center;
margin-top: -0.5em;
line-height: 1em;
"
>
资æºåŠ è½½...
</div>
</div>
<script src="/static/js/da8a876a19ad89802b15.js"></script>
</body>
</html>
》》》结束
Process finished with exit code 0
这时,我们获取的源码才是网站真正的网页代码,反反爬成功!但通过观察,可以发现获取的网页源码存在乱码问题,那么,接下来我们就来看看如何解决乱码问题吧↓↓↓↓
为什么会出现乱码情况?
分析:
每一种编码格式都不同,如果没有使用正确的编码格式进行编译就会出现乱码或者错误。其道理就如同你拿着自家房间钥匙去开他人房间,互不照应,自然就无法正常进门
解决方法:
1、在对应网站界面空白处右键,选择“查看网页源代码”(或在对应界面按Ctrl+U,不同浏览器可能会有些许差异)
2.找取编码信息(基本每个网站都不同,但编码格式信息一般会在前几行中声明)
知道编码格式为UTF-8后,那么接下来我们就指定编译格式为UTF-8
实例代码:
import requests
headers = {
'Referer': 'https://www.qidian.com/',
'cache-control': 'no-cache',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'accept-language': 'zh-CN,zh;q=0.9',
'if-none-match':'W/"60180217-2dc9a"',
'Host': 'www.bilibili.com',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'cross-site',
'sec-fetch-user': '?1',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
}
url = 'http://www.qidian.com/'
resp = requests.get(url=url,headers=headers)
# print(resp.request.headers)
print(resp.content.decode('utf-8'))
文章中所述技术可以运用在任何相似问题网站上!
下一篇内容大体预告:
批量爬取小说网站的小说并保存为TXT文件
END
PS:文中表情包来自网络