很久之前就学习了Python的爬虫了,也用来做过一些项目(主要是一些课程项目),但时间比较紧,一直没有空把它写下来,这个暑假,我可能会逐渐更新Python爬虫的相关知识。
项目1:实现批量爬取百度图片
先简单的介绍下这个项目。当你需要下载大量图片的时候,或许你会去百度图片里一张张右键下载,但这样未免太麻烦了,有了这个工具,你直接运行下程序,输入你想要下载图片的关键字,然后输入你想要下载图片的数量,你就成功下载图片了!
下面给下演示程序的截图:
几秒钟后,我去C盘文件夹下,就有了30张,张天爱的图片啦!
是不是觉得,这样下载起来比较方便........
好了,言归正传,下面开始一步步教大家,怎么实现它!
1. Python的IDE,我想大家应该都有吧,我用的是pycharm,大家可以去官网上下载,这里顺带给大家推荐一个免费试用它的方法,当然,仅限于在校大学生(如果你是高中生的话,可能需要麻烦一点,去百度找注册码,大概每个月会更新一次的样子)
首先,你先到jetBrains 官网,官网链接在这!打开后。
你点击右上角的人物标志,进入账号登录页面。
之后,你在打开这个注册账号的链接:学生账号注册链接,
点击立即申请!
你会进入这个页面:
这里需要一个学校的公邮,这个公邮去哪里找呢?你可以去你所在学校的官网找找,每个在校大学生都可以申请200个学校公邮的(反正我们学校是这样),你可以搜索你们学校的邮箱系统,去查看具体怎么申请,每个学校可能不同。
申请好了以后,你在回到一开始让你进入的登录页面,登录以后,就可以免费下载使用了。
2 .安装爬虫需要的包
(1)如果你使用的是pycharm,那么你安装包会非常的方便,在pycharm里找的Terminal 点击,输入pip install ....就可以安装包了,当然如果是你首次运行的话,可能需要你更新pip工具,这你最好去官网重新下载下pip,这样你以后会很方便,这里就不在具体讲怎么更新pip了,以后有时间在写写吧。
(2) 依次键入pip install BeautifulSoup
pip insatll requests
pip install lxml
(3)下面将分别介绍他们的用途:
BeautifulSoup 是用来获取一个页面里面的各个标签及里面的内容,我们主要用到它里面的find(),find_All()函数,具体用法将在后面一一介绍
requests 是用来获取网页信息的,也就是说,我们给它一个url,它能把这个url对应的页面信息全部反馈给我们,这时候我们在用beautifulSoup里的函数对他们进行处理
lxml 是一个解析器,python里有专门的解析器,html.parser,但是lxml的解析速度优于html_parser,所以建议使用lxml
3. Python正则表达式基础
要想提升写爬虫的能力,那么你必须学会正则表达式,它可以让你用简短的代码实现你想要的功能。
详细的知识,可以到这里去看.python 正则表达式
下面我会介绍,本次项目里使用到的技巧:
首先你先打开百度图片 ,也就是这个页面 百度图片
然后,你可以随便输入你想要查看的图片....(不好意思,我还是输入了,zhang tian ai)
注意:先点击右上角,切换成传统翻页版,因为这样有利于我们爬取图片!这里一定要注意,很多网友问我,为啥他打开百度图片,每一页不是60张图片。因为你直接打开的网页,不便于翻页操作,并且每一页的图片数量不相同。所以,我选择爬取的方法是,从传统翻页版爬取图片。
接着,你右键检查网页源代码(如果你用的是谷歌浏览器),那么你可以在里面直接搜索 objURL 或者URL
现在我们发现了我们需要图片的url了,现在,我们要做的就是将这些信息爬取出来(网页中有objURL,hoverURL...但是我们用的是objURL,因为这个是原图),如何获取objURL?当然你可以暴力写个程序跑一遍,但是这程序写起来.....
那我们该如何用正则表达式实现呢?其实只需要一行代码.....
就是这么简单,我想你如果看了正则表达式,一定可以轻松的写出或者理解这句话。
经过我的实验,我发现传统翻页版的百度图片,每一页有60张图片。这也是为啥后面我写代码,用了t+60。
4 . BeautifulSoup知识介绍
同样的我先给出文档链接,具体细节大家自己研究,我这里只介绍这个项目用到的知识。BeautifulSoup 文档
我们主要用到的是find()和find_All()函数:
5. requests 介绍
requests博大精深,我们这里只不过是用了它的一个功能而已。
html = requests.get(url) 我们将url传进去,它就会得到这个url里面的信息,具体的,大家可以在python里运行试试.
6. 项目实现思路
首先需要写一个下载图片的函数,其次还有检测图片数量的函数,还有最后的推荐函数(推荐函数,主要是根据你键入的文本,在百度图片里找到相似的内容,返回给用户,类似于百度搜索的最下面)
首先是图片下载函数:下面是部分代码
具体思路就是根据正则表达式,找到url,然后完成下载。
其次是推荐函数:
推荐函数,主要公能是把百度的相关搜索提示返回给用户,实现很简单,但需要注意编码的问题(关于python编码格式的问题,我觉得能写10000字,以后有空再慢慢写吧)。
还有是检测图片数量函数,它的主要思路是通过计算能翻的页数来估算总数量,比如一个页面有20张图片,那么我点下一页50次,那么就说明有1000张图片....虽然这样很傻(哈哈)
因为有些图片可能有很多张(估计要翻页10000多次),所以为了能在几秒内下载好图片,我把图片是上限设为了1020张,也就是说即使有100000张图片,我也就先告诉你只有1020张(当然你也可以把它设置为无限,可能会慢一点)
7 主函数
主函数主要是一些逻辑上的问题,为的就是让用户使用更便捷而已,具体我就不一一解释,我想大家看源码比看我写 的文字更有感觉。
之前会出现下载重复的bug,现在已经解决了。
8 源代码:
-
# -*- coding: utf-8 -*-
-
"""
-
Created on Sun Sep 13 21:32:25 2020
-
-
@author: ydc
-
"""
-
-
-
-
-
import re
-
import requests
-
from urllib
import error
-
from bs4
import BeautifulSoup
-
import os
-
-
num =
0
-
numPicture =
0
-
file =
''
-
List = []
-
-
-
def Find(url, A):
-
global List
-
print(
'正在检测图片总数,请稍等.....')
-
t =
0
-
i =
1
-
s =
0
-
while t <
1000:
-
Url = url + str(t)
-
try:
-
# 这里搞了下
-
Result = A.get(Url, timeout=
7, allow_redirects=
False)
-
except BaseException:
-
t = t +
60
-
continue
-
else:
-
result = Result.text
-
pic_url = re.findall(
'"objURL":"(.*?)",', result, re.S)
# 先利用正则表达式找到图片url
-
s += len(pic_url)
-
if len(pic_url) ==
0:
-
break
-
else:
-
List.append(pic_url)
-
t = t +
60
-
return s
-
-
-
def recommend(url):
-
Re = []
-
try:
-
html = requests.get(url, allow_redirects=
False)
-
except error.HTTPError
as e:
-
return
-
else:
-
html.encoding =
'utf-8'
-
bsObj = BeautifulSoup(html.text,
'html.parser')
-
div = bsObj.find(
'div', id=
'topRS')
-
if div
is
not
None:
-
listA = div.findAll(
'a')
-
for i
in listA:
-
if i
is
not
None:
-
Re.append(i.get_text())
-
return Re
-
-
-
def dowmloadPicture(html, keyword):
-
global num
-
# t =0
-
pic_url = re.findall(
'"objURL":"(.*?)",', html, re.S)
# 先利用正则表达式找到图片url
-
print(
'找到关键词:' + keyword +
'的图片,即将开始下载图片...')
-
for each
in pic_url:
-
print(
'正在下载第' + str(num +
1) +
'张图片,图片地址:' + str(each))
-
try:
-
if each
is
not
None:
-
pic = requests.get(each, timeout=
7)
-
else:
-
continue
-
except BaseException:
-
print(
'错误,当前图片无法下载')
-
continue
-
else:
-
string = file +
r'\\' + keyword +
'_' + str(num) +
'.jpg'
-
fp = open(string,
'wb')
-
fp.write(pic.content)
-
fp.close()
-
num +=
1
-
if num >= numPicture:
-
return
-
-
-
if __name__ ==
'__main__':
# 主函数入口
-
-
##############################
-
# 这里加了点
-
headers = {
-
'Accept-Language':
'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
-
'Connection':
'keep-alive',
-
'User-Agent':
'Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0',
-
'Upgrade-Insecure-Requests':
'1'
-
}
-
-
A = requests.Session()
-
A.headers = headers
-
###############################
-
-
word = input(
"请输入搜索关键词(可以是人名,地名等): ")
-
# add = 'http://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=%E5%BC%A0%E5%A4%A9%E7%88%B1&pn=120'
-
url =
'https://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=' + word +
'&pn='
-
-
# 这里搞了下
-
tot = Find(url, A)
-
Recommend = recommend(url)
# 记录相关推荐
-
print(
'经过检测%s类图片共有%d张' % (word, tot))
-
numPicture = int(input(
'请输入想要下载的图片数量 '))
-
file = input(
'请建立一个存储图片的文件夹,输入文件夹名称即可')
-
y = os.path.exists(file)
-
if y ==
1:
-
print(
'该文件已存在,请重新输入')
-
file = input(
'请建立一个存储图片的文件夹,)输入文件夹名称即可')
-
os.mkdir(file)
-
else:
-
os.mkdir(file)
-
t =
0
-
tmp = url
-
while t < numPicture:
-
try:
-
url = tmp + str(t)
-
-
# 这里搞了下
-
result = A.get(url, timeout=
10, allow_redirects=
False)
-
except error.HTTPError
as e:
-
print(
'网络错误,请调整网络后重试')
-
t = t +
60
-
else:
-
dowmloadPicture(result.text, word)
-
t = t +
60
-
-
print(
'当前搜索结束,感谢使用')
-
print(
'猜你喜欢')
-
for re
in Recommend:
-
print(re, end=
' ')
好了,就先写这么多。欢迎大家转载。如有问题,欢迎给我留言。
2019年4月2日 第3次更新
这次有网友想要爬取大量的图片作为训练材料。他想要300种不同的图片,每种100张,如果还是按之前的代码去运行,就需要他输入300次图片的名称,这样是非常浪费时间的。所以这里对代码进行一些改进,你只需要把你想要爬取图片的名称,编辑到一个txt文件,然后输入你需要的数量就行。
使用方法:
首先将你需要下载的图片名称写到一个txt文本上,文本的名字叫name即可。
按行输入,每行放一个名字。
将name.txt放入和你当前python文件同一目录下即可。
代码:
-
# -*- coding: utf-8 -*-
-
"""
-
Created on Sun Sep 13 21:35:34 2020
-
-
@author: ydc
-
"""
-
-
import re
-
import requests
-
from urllib
import error
-
from bs4
import BeautifulSoup
-
import os
-
-
num =
0
-
numPicture =
0
-
file =
''
-
List = []
-
-
-
def Find(url, A):
-
global List
-
print(
'正在检测图片总数,请稍等.....')
-
t =
0
-
i =
1
-
s =
0
-
while t <
1000:
-
Url = url + str(t)
-
try:
-
# 这里搞了下
-
Result = A.get(Url, timeout=
7, allow_redirects=
False)
-
except BaseException:
-
t = t +
60
-
continue
-
else:
-
result = Result.text
-
pic_url = re.findall(
'"objURL":"(.*?)",', result, re.S)
# 先利用正则表达式找到图片url
-
s += len(pic_url)
-
if len(pic_url) ==
0:
-
break
-
else:
-
List.append(pic_url)
-
t = t +
60
-
return s
-
-
-
-
def recommend(url):
-
Re = []
-
try:
-
html = requests.get(url, allow_redirects=
False)
-
except error.HTTPError
as e:
-
return
-
else:
-
html.encoding =
'utf-8'
-
bsObj = BeautifulSoup(html.text,
'html.parser')
-
div = bsObj.find(
'div', id=
'topRS')
-
if div
is
not
None:
-
listA = div.findAll(
'a')
-
for i
in listA:
-
if i
is
not
None:
-
Re.append(i.get_text())
-
return Re
-
-
def dowmloadPicture(html, keyword):
-
global num
-
# t =0
-
pic_url = re.findall(
'"objURL":"(.*?)",', html, re.S)
# 先利用正则表达式找到图片url
-
print(
'找到关键词:' + keyword +
'的图片,即将开始下载图片...')
-
for each
in pic_url:
-
print(
'正在下载第' + str(num +
1) +
'张图片,图片地址:' + str(each))
-
try:
-
if each
is
not
None:
-
pic = requests.get(each, timeout=
7)
-
else:
-
continue
-
except BaseException:
-
print(
'错误,当前图片无法下载')
-
continue
-
else:
-
string = file +
r'\\' + keyword +
'_' + str(num) +
'.jpg'
-
fp = open(string,
'wb')
-
fp.write(pic.content)
-
fp.close()
-
num +=
1
-
if num >= numPicture:
-
return
-
-
-
if __name__ ==
'__main__':
# 主函数入口
-
-
-
headers = {
-
'Accept-Language':
'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
-
'Connection':
'keep-alive',
-
'User-Agent':
'Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0',
-
'Upgrade-Insecure-Requests':
'1'
-
}
-
-
A = requests.Session()
-
A.headers = headers
-
-
-
###############################
-
-
-
tm = int(input(
'请输入每类图片的下载数量 '))
-
numPicture = tm
-
line_list = []
-
with open(
'./name.txt', encoding=
'utf-8')
as file:
-
line_list = [k.strip()
for k
in file.readlines()]
# 用 strip()移除末尾的空格
-
-
for word
in line_list:
-
url =
'https://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=' + word +
'&pn='
-
tot = Find(url,A)
-
Recommend = recommend(url)
# 记录相关推荐
-
print(
'经过检测%s类图片共有%d张' % (word, tot))
-
file = word +
'文件'
-
y = os.path.exists(file)
-
if y ==
1:
-
print(
'该文件已存在,请重新输入')
-
file = word+
'文件夹2'
-
os.mkdir(file)
-
else:
-
os.mkdir(file)
-
t =
0
-
tmp = url
-
while t < numPicture:
-
try:
-
url = tmp + str(t)
-
#result = requests.get(url, timeout=10)
-
# 这里搞了下
-
result = A.get(url, timeout=
10, allow_redirects=
False)
-
print(url)
-
except error.HTTPError
as e:
-
print(
'网络错误,请调整网络后重试')
-
t = t +
60
-
else:
-
dowmloadPicture(result.text, word)
-
t = t +
60
-
numPicture = numPicture + tm
-
-
print(
'当前搜索结束,感谢使用')
如遇到bug或者有新的需求,可以给我留言。
最新情况:由于笔者最近忙于备考,很多找我问问题的朋友我没能尽力的去帮忙。大家给我的留言我可能不能及时回复,同时很多加我微信好友的,我也不能及时回复。但我还是会抽时间尽力解决大家提出的问题。(2019.06.16)
2019年8月4日 第4次更新
还是有很多同学问我怎么更改每次下载的图片数量,我一开始设置的最高只能下载1060张:
更改方法:把代码中含有1000的地方,全部换成你想要的数字。(例如每类图片都想下载5000张,那么你把1000改成5000)
最近有很多网友留言和加我微信。我都没有回复,原因在于笔者正在备考。明年才有空。2019.11.29
2020.4.13更新。
最后在写一下,我代码里面用了t+60是因为,每一页有60张图片,我爬完一页,就代表已经获得60张图片,然后翻页,开始爬取下一页。
另:这个项目是根据网友们的反馈,才得到不断的完善。这已经不再是我一个人的项目了,而是属于各位一起帮忙反馈bug的网友们。非常感谢各位的反馈。
目前笔者仍然没有时间,之前收到一位网友的反馈,一直没有更新。等我5月复试结束以后,我会更新的。
若有网友发现问题,也欢迎继续反馈给我,我后面会找时间更新的。
2020.9.13
之前遇到的问题已经解决。感谢网友们的大力支持。
转载:https://blog.csdn.net/qq_40774175/article/details/81273198