博主纯手工打字,转载请注明出处!各位大佬不喜勿喷!
先笼统说一下本文针对ftp协议下的文件夹和文件递归下载方法:
(I)使用FileZilla工具进行下载;
(II)使用脚本爬取;
(III)使用命令直接下载;
(IV)python脚本直接下载。
最近需要下载一批新的固件,本来是准备写脚本爬取的,但是使用scrapy框架爬取的时候,发现并不能有效地支持ftp协议的情况,貌似很好地支持http和https协议的网址。
需要研究和处理内容的网址为:ftp://ftp2.dlink.com/
(1)通过向大佬同学东神咨询和学习后,得知存在一些下载工具或者使用命令准们针对ftp协议的文件传输下载会更好。
在windows和linux或者os系统下,一个很好的图形界面工具是FileZilla,能够很好地支持文件夹和文件的递归下载:
必要的时候需要输入用户名和密码。对于这个ftp服务器,暂时还是不需要的。
(2)然而使用scrapy框架爬取,只是针对网页内容的爬取比较好。当然也存在一些扩展插件,支持ftp的爬取。如下面这个博客里面就提供了一个很好的使用案例和方法。
参考链接:https://www.xuebuyuan.com/322048.html
#! -*- encoding:utf-8 -*-
#file is 'ftp.py', sys.path:'src.middleware.ftp.FtpDownloadHandler'
__author__ = 'C.L.TANG'
import urllib2
from scrapy.http import Response
class FtpDownloadHandler(object):
def download_request(self, request, spider):
"""Return a deferred for the HTTP download"""
handler = urllib2.FTPHandler()
req = urllib2.Request(url = request.url)
opener = urllib2.build_opener(handler)
f = opener.open(req)
b = f.read()
print len(b)
respcls = Response(url = request.url, body=b, request = request)
return respcls
##然后在自己项目的settings.py文件中指定:
DOWNLOAD_HANDLERS = {'ftp' : 'src.middleware.ftp.FtpDownloadHandler'}
##在爬虫类中有:
#! -*- encoding:utf-8 -*-
from scrapy.selector import HtmlXPathSelector
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.http import Request
class ShopSpider(CrawlSpider):
name = '958shop'
allowed_domains = ['958shop.com']
def start_requests(self):
request = Request(url = 'ftp://b9:[email protected]/2011/11/15/52076863815926.jar')
request.callback = self.down_debug_html
return [request,]
def down_debug_html(self, response):
#在这里调用存入下载链接地址的方法.
#file_name = response.meta['file_name']
print response.url
filename = 'debug.html'
open(filename, 'wb').write(response.body)
针对上面的这个方法,本博主还没有着手实现。有志者可以着手试试!顺便写个留言博客地址让我膜拜一下。
(3)关于使用命令于是就各种百度查找,使用命令都需要知道ftp服务器的用户名和密码,但是我一脸懵逼,因为我现在只知道对应的ftp地址,哪里知道什么用户名和密码。这就很气了!
于是就使用wireshark进行抓包分析和观望,得到了用户名和密码:
username = anonymous, [email protected]
但是第二次我再次抓包的时候,发现登录的密码已经变成了mozilla@example,我尝试把密码改为这个进行测试的时候,结果显示也是能够直接获取数据的。然后我就猜测匿名登录的时候密码为空的时候,于是我就测试一下发现的确密码为空的时候是可以登录,所以验证密码为任意。
于是我又大胆地猜测如果用户名也为空的话,是不是能通过?于是我就把用户名和密码都置为空,但是好像无法登陆!
于是我又猜测,是不是只用用户名不为空就可以呢?我就把用户名改为不是anonymous这个内容,结果报错了:
在得知这些用户明和密码之后就能够很好地使用命令了。参考链接https://blog.csdn.net/junqing124/article/details/51558197
就构造了下面这条链接,但是并非那么地好用,因为下载速度很是慢啊。
wget -r -nH -P ./ ftp://ftp2.dlink.com/PRODUCTS/* --f --ftp-user=anonymous [email protected]
在接下来本博主准备写一个脚本处理问价,下载文件内容,猜测应该会好用很多。
(4)python脚本下载
本博主写的python下载内容是参考这个的,由于项目内容,暂时不便放出来。需要的同学参考这个自己写一个吧。
# -*- encoding: utf8 -*-
import os
import sys
import ftplib
sys.setdefaultencoding('gbk')
XFER_FILE = 'FILE'
_XFER_DIR = 'DIR'
class FTPSync(object):
def __init__(self):
self.conn = ftplib.FTP('192.168.8.5', 'tools', 'tools')
self.conn.cwd('/meteor') # 远端FTP目录
os.chdir('./aa') # 本地下载目录
def get_dirs_files(self):
u''' 得到当前目录和文件, 放入dir_res列表 '''
dir_res = []
self.conn.dir('.', dir_res.append)
files = [f.split(None, 8)[-1] for f in dir_res if f.startswith('-')]
dirs = [f.split(None, 8)[-1] for f in dir_res if f.startswith('d')]
return (files, dirs)
def walk(self, next_dir):
print 'Walking to', next_dir
self.conn.cwd(next_dir)
try:
os.mkdir(next_dir)
except OSError:
pass
os.chdir(next_dir)
ftp_curr_dir = self.conn.pwd()
local_curr_dir = os.getcwd()
files, dirs = self.get_dirs_files()
print "FILES: ", files
print "DIRS: ", dirs
for f in files:
print next_dir, ':', f
outf = open(f, 'wb')
try:
self.conn.retrbinary('RETR %s' % f, outf.write)
finally:
outf.close()
for d in dirs:
os.chdir(local_curr_dir)
self.conn.cwd(ftp_curr_dir)
self.walk(d)
def run(self):
self.walk('.')
def main():
f = FTPSync()
# f.run()
if __name__ == '__main__':
main()
class Xfer(object):
'''''
@note: upload local file or dirs recursively to ftp server
'''
def __init__(self):
self.ftp = None
def __del__(self):
pass
def setFtpParams(self, ip, uname, pwd, port = 21, timeout = 60):
self.ip = ip
self.uname = uname
self.pwd = pwd
self.port = port
self.timeout = timeout
def initEnv(self):
if self.ftp is None:
self.ftp = ftplib.FTP()
print '### connect ftp server: %s ...'%self.ip
self.ftp.connect(self.ip, self.port, self.timeout)
self.ftp.login(self.uname, self.pwd)
print self.ftp.getwelcome()
def clearEnv(self):
if self.ftp:
self.ftp.close()
print '### disconnect ftp server: %s!'%self.ip
self.ftp = None
def uploadDir(self, localdir='./', remotedir='./'):
if not os.path.isdir(localdir):
return
self.ftp.cwd(remotedir)
for file in os.listdir(localdir):
src = os.path.join(localdir, file)
if os.path.isfile(src):
self.uploadFile(src, file)
elif os.path.isdir(src):
try:
self.ftp.mkd(file)
except:
sys.stderr.write('the dir is exists %s'%file)
self.uploadDir(src, file)
self.ftp.cwd('..')
def uploadFile(self, localpath, remotepath='~/test'):
if not os.path.isfile(localpath):
return
print '+++ upload %s to %s:%s'%(localpath, self.ip, remotepath)
self.ftp.storbinary('STOR ' + remotepath, open(localpath, 'rb'))
def __filetype(self, src):
if os.path.isfile(src):
index = src.rfind('\\')
if index == -1:
index = src.rfind('/')
return _XFER_FILE, src[index+1:]
elif os.path.isdir(src):
return _XFER_DIR, ''
def upload(self, src):
filetype, filename = self.__filetype(src)
self.initEnv()
if filetype == _XFER_DIR:
self.srcDir = src
self.uploadDir(self.srcDir)
elif filetype == _XFER_FILE:
self.uploadFile(src, filename)
self.clearEnv()
if __name__ == '__main__':
srcDir = r"/Users/meteor/Desktop/gitlab/aa"
# srcFile = r'C:\sytst\sar.c'
xfer = Xfer()
xfer.setFtpParams('192.168.8.5', 'tools', 'tools')
xfer.upload(srcDir)
xfer.upload(srcFile)
参考链接:
https://blog.csdn.net/osmeteor/article/details/53812057
https://blog.csdn.net/u010412833/article/details/73649274?locationNum=7&fps=1
http://blog.chinaunix.net/uid-21516619-id-1825037.html