用MongoDB数据库记录已下载过的地址
使用PyMongo模块
直接代码:
主程序:
#导入需要的包
from bs4 import BeautifulSoup
import os
from BackClimb import down
from pymongo import MongoClient
import datetime
#建立一个抓图类
class mzitu():
#创建数据库调用函数
def __init__(self):
client = MongoClient()##与MongoDB建立链接,这是默认链接本地MongoDB数据库
db = client['meinvxiezhenji']##选择一个数据库
self.meizitu_collection = db['meizitu']##在meinvxiezhenji这个数据库中,选择一个集合
self.title = ''##用来保存页面主题
self.url = ''##用来保存页面地址
self.img_urls = []##初始化一个列表,用来保存图片地址
#主入口函数
def all_url(self,url):
html = down.get(url,3) ##调用request函数吧地址传进去,返回一个response
all_a = BeautifulSoup(html.text,'lxml').find('div',class_='all').find_all('a')##用Soup对象的find方法找标签先查找class为all的div标签,然后查找所有标签。find_all是查找所有标签
for a in all_a:
title = a.get_text()
self.title = title ##将主题保存到self.title中
print(u'开始保存:',title)##提示保存XXX
path = str(title).replace('?','_')##设置名字变量,将?替换成_
self.mkdir(path)##调用mkdir函数创建文件夹,path代表的是标题名
os.chdir('F:\mzitu\\'+path) ##改变工作路径
href = a['href']##取出里面的href属性
self.url = href ##将页面地址保存到self.url中
if self.meizitu_collection.find_one({'主题页面':href}): ##判断这个主题是否已经在数据库中,不在就运行eles下的内容,在则忽略。
print(u'这个页面已经爬过了!')
else:
self.html(href)##调用html函数吧href参数传递过去,href是套图的地址
#设置一个函数处理套图地址获得图片的页面地址
def html(self,href):
html = down.get(href,3)##调用request函数把套图地址传进去,返回一个response
max_span = BeautifulSoup(html.text,'lxml').find_all('span')[10].get_text()##查找所有的标签获取最后一个标签中的文本也就是最后一个页面了
page_num =0 ##这个当作计数器用,用来判断图片是否下载完毕
for page in range(1,int(max_span)+1):##用range产生页面序列
page_num = page_num+1 ##每for循环一次+1,当page_num等于max_span的时候,就证明我们在下载最后一张图片了
page_url = href + '/'+str(page)##手动拼接每一个页面地址
self.img(page_url,max_span,page_num)##调用img函数,把上面需要的两个变量,传递给下一个函数。
#设置一个函数处理图片页面地址获得图片的实际地址
def img(self,page_url,max_span,page_num):
img_html = down.get(page_url,3)##调用request函数把图片页面地址传进去,返回一个response
img_url = BeautifulSoup(img_html.text,'lxml').find('div',class_='main-image').find('img')['src']##用img_Soup对象的find方法找标签先查找class为main-image的div标签,然后查找标签里面的src。
self.img_urls.append(img_url)##每一次for page in range(1,int(max_span)+1)获取到的图片地址都会添加到img_urls这个初始化的列表中
if int(max_span) == page_num:##传递下来的两个参数用上了,当max_span和page_num相等是,就是最后一张图片,最后一次下载图片并保存到数据库中。
self.save(img_url)
post = {##这是构造一个字典,
'标题':self.title,'主题页面':self.url,'图片地址':self.img_urls,'获取时间':datetime.datetime.now()
}
self.meizitu_collection.save(post)##将post中的内容写入数据库
print (u'插入数据库成功')
else: ##max_span 不等于page_num的时候执行下面这段
self.save(img_url)##调用save函数保存图片,把img_url地址传递过去
#设置一个保存图片的函数
def save(self,img_url):
name = img_url[-9:-4]##取url的倒数第四至第九位做图片的名字
print('开始保存:',img_url)
img = down.get(img_url,3)##调用request函数把图片地址传进去,返回一个response
f = open(name+'.jpg','ab')##写入多媒体文件必须要b这个参数
f.write(img.content)##多媒体文件要用conctent
f.close()##关闭文件对象
#创建一个函数用来创建文件夹
def mkdir(self,path):
path = path.strip() ##去除path前后空格
isExists = os.path.exists(os.path.join('F:\mzitu',path))##join将各部分合成一个路径名。os.path.exists判断后面的路径是否存在
if not isExists: ##如果为False,创建文件夹
print(u'创建了一个名字叫做',path,u'的文件夹!')
os.makedirs(os.path.join('F:\mzitu',path))##创建多层文件夹,用join合成单独的一个路径文件夹
return True
else:
print(u'名字叫做',path,u'的文件夹已经存在了!')
return False
#
# #创建获取网页response的函数并返回
# def request(self,url):
# headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'}#设置浏览器请求头
# content = requests.get(url,headers=headers) ##使用requests中的get方法获取页面的内容,加上浏览器请求头
# return content
Mzitu = mzitu() ##实例化
#这就是入口!
Mzitu.all_url('http://www.mzitu.com/all')
下载模块:
import requests
import re
import random
import time
#创建一个反反爬的类
class download:
def __init__(self):
self.iplist = [] ##初始化一个list用来存放获取到的ip
html = requests.get(' http://haoip.cc/tiqu.htm')##使用requests中的get方法获取页面的内容
iplistn = re.findall(r'r/>(.*?)0: ##num_retries是限定的重试次数
time.sleep(10) ##延迟10秒
print(u'获取网页出错,10s后将获取倒数第:',num_retries,u'次')
return self.get(url,timeout,num_retries-1)##调用自身,并减1,实现循环6次
else:
print(u'开始使用代理')
time.sleep(10)
IP = ''.join(str(random.choice(self.iplist)).strip())##将从self.iplist中随机获取的字符串处理成需要的格式。去除两边空格后,用join拼接?
proxy = {'http':IP}
return self.get(url,timeout,proxy)##代理不为空的时候
else: ##当代理不为空
try:
IP = ''.join(str(random.choice(self.iplist)).strip())##将从self.iplist中随机获取的字符串处理成需要的格式。去除两边空格后,用join拼接?
proxy = {'http':IP}##构造成一个代理
return requests.get(url,headers=headers,proxies = proxy,timeout=timeout)##使用代理获取response
except:
if num_retries >0:
time.sleep(10)
IP = ''.join(str(random.choice(self.iplist)).strip())
proxy = {'http':IP}
print(u'正在更换代理,10s后将重新获取倒数第',num_retries,u'次')
print(u'当前代理是:',proxy)
return self.get(url,timeout,proxy,num_retries-1)
else:
print(u'代理也不好使!取消代理')
return self.get(url,3)
down = download()