如何使用 Scrapy 下载文件?
Scrapy 是一个快速的高级网页抓取和网页抓取框架,用于抓取网站并从其页面中提取结构化数据。它可用于广泛的用途,从数据挖掘到监控和自动化测试。在本教程中,我们将探索如何使用scrapy crawl spider 下载文件。
对于初学者来说,网络爬虫是一种遍历万维网以下载与特定主题相关的信息的方法。要记住的一件事是,并非所有网站都允许您抓取他们的页面,因此在尝试抓取页面之前参考他们的 robots.txt 文件始终是一个好习惯。
第 1 步:安装软件包:
在我们开始编码之前,我们需要安装 Scrapy 包
pip install scrapy
第 2 步:创建项目
# scrapyProject is the name we chose for
# the folder that will contain the project
mkdir scrapyProject
cd scrapyProject
# downFiles is the name of the project
scrapy startproject downFiles
在终端中运行上述代码后的输出如下:
第 3 步:选择蜘蛛模板
Scrapy 自带 4 个蜘蛛模板,分别是:
- 基础:通用
- crawl: 用于爬行,或跟随链接(下载文件首选)
- csvfeed: 用于解析 CSV 文件
- xmlfeed:用于解析 XML 文件
在本教程中,我们将使用爬网蜘蛛模板并在此基础上进一步构建。
在scrapy中查看可用的蜘蛛模板:
scrapy genspider -l
在我们开始构建蜘蛛的基本结构之前,请确保您在步骤 2 中创建的项目目录(包含 spider.cfg 文件的目录)中工作
要更改您的目录:
# the project name we had decided was
# downFiles in step2
cd downFiles
创建爬行蜘蛛的基本结构:
scrapy genspider -t crawl nirsoft www.nirsoft.net # nirsoft is the spider name, www.nirsoft.com is the website (domain) we will be crawling
将使用以下内容创建一个带有蜘蛛名称的新Python文件:
该文件将位于
…\scrapyProject\downFiles\downFiles\spiders\nirsoft.py
在哪里
- scrapyProject 是包含项目的目录名
- downFiles 是项目名称
- nirsoft.py 是新创建的“空”蜘蛛
代码:
Python3
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class NirsoftSpider(CrawlSpider):
name = 'nirsoft'
allowed_domains = ['www.nirsoft.net']
start_urls = ['http://www.nirsoft.net/']
rules = (
Rule(LinkExtractor(allow=r'Items/'),
callback='parse_item', follow=True),
)
def parse_item(self, response):
item = {}
return item
Python3
rules = (
Rule(LinkExtractor(allow = r'Items/'),
callback = 'parse_item',
follow = True),
)
Python3
rules = (
Rule(LinkExtractor(allow=r'utils/'),
callback='parse_item', follow = True),
)
Python3
def parse_item(self, response):
file_url = response.css('.downloadline::attr(href)').get()
file_url = response.urljoin(file_url)
yield {'file_url': file_url}
Python3
class DownfilesItem(scrapy.Item):
# define the fields for your item here like:
file_urls = scrapy.Field()
files = scrapy.Field
Python3
def parse_item(self, response):
file_url = response.css('.downloadline::attr(href)').get()
file_url = response.urljoin(file_url)
item = DownfilesItem()
item['file_urls'] = [file_url]
yield item
Python3
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from downFiles.items import DownfilesItem
Python3
def parse_item(self, response):
file_url = response.css('.downloadline::attr(href)').get()
file_url = response.urljoin(file_url)
file_extension = file_url.split('.')[-1]
if file_extension not in ('zip', 'exe', 'msi'):
return
item = DownfilesItem()
item['file_urls'] = [file_url]
item['original_file_name'] = file_url.split('/')[-1]
yield item
Python3
class DownfilesItem(scrapy.Item):
# define the fields for your item here like:
file_urls = scrapy.Field()
original_file_name = scrapy.Field()
files = scrapy.Field
Python3
from scrapy.pipelines.files import FilesPipeline
class DownfilesPipeline(FilesPipeline):
def file_path(self, request, response=None, info=None):
file_name: str = request.url.split("/")[-1]
return file_name
这是一个“空”的爬虫。执行时不会产生任何结果。为了提取信息,我们需要告诉蜘蛛它需要爬取哪些链接。
注意:这就是 Scrapy 与其他流行的网络爬行包(如Selenium)不同的地方, Selenium如果未指定,则爬取所有数据(即使不必要)。此功能使 Scrapy 比Selenium更快。
第 4 步:定义链接提取规则
蟒蛇3
rules = (
Rule(LinkExtractor(allow = r'Items/'),
callback = 'parse_item',
follow = True),
)
上面的代码段是用来处理蜘蛛将要爬取的链接的。可以使用多个命令来制定规则,但在本教程中,我们将仅使用少数几个常用命令。我们将尝试下载 nirsoft.net 提供的一些工具 所有工具或实用程序都在其实用程序下可用,因此所有相关链接都遵循给定的模式:
https://www.nirsoft.net/utils/...
Example:
https://www.nirsoft.net/utils/simple_program_debugger.html
https://www.nirsoft.net/utils/web_browser_password.html
https://www.nirsoft.net/utils/browsing_history_view.html
所以上面的代码段将被编辑如下:
蟒蛇3
rules = (
Rule(LinkExtractor(allow=r'utils/'),
callback='parse_item', follow = True),
)
第四步:解析抓取到的页面
现在我们已经设置了要抓取的链接,接下来我们需要定义蜘蛛应该抓取的内容。为此,我们将不得不检查相关页面。前往上述任何示例并打开检查元素模式(对于 Windows,ctrl+shift+c,对于 MacOS,cmd+shift+c)
- 我们可以看到下载链接都是一个锚标签(a),类名是“downloadline”(a.downloadline)
- 所以现在我们将在 CSS 选择器中使用它并提取锚标记的 href 属性
- 为了让爬虫高效工作,我们还需要将相对链接转换为绝对链接。幸运的是,最新版本的 Scrapy 使我们能够通过一个简单的方法来做到这一点: urljoin()
因此 parse_item() 方法将如下所示:
蟒蛇3
def parse_item(self, response):
file_url = response.css('.downloadline::attr(href)').get()
file_url = response.urljoin(file_url)
yield {'file_url': file_url}
如果我们在此状态下运行爬虫,我们将获得 nirsoft 中所有可用实用程序的链接。
scrapy crawl nirsoft
对于初学者:我建议现在不要运行上面的命令,因为你的命令提示符将充斥着大量的 URL,这些 URL 滚动得太快,你的眼睛无法感知任何东西。
相反,让我们继续下一步
步骤 5:下载文件
最后,我们都在等待的那一刻,下载文件。但是,在我们开始之前,我们需要编辑最初创建蜘蛛时创建的项目类。该文件可以在以下位置找到:
...\scrapyProject\downFiles\downFiles\items.py
在哪里
- scrapyProject 是包含项目的目录名
- downFiles 是项目名称
- items.py 是相关项目的类
项目类必须编辑如下:
蟒蛇3
class DownfilesItem(scrapy.Item):
# define the fields for your item here like:
file_urls = scrapy.Field()
files = scrapy.Field
现在我们更新蜘蛛脚本以使用我们定义的数据字段
蟒蛇3
def parse_item(self, response):
file_url = response.css('.downloadline::attr(href)').get()
file_url = response.urljoin(file_url)
item = DownfilesItem()
item['file_urls'] = [file_url]
yield item
您还必须将之前定义的项目类导入到蜘蛛脚本中,因此蜘蛛脚本的导入部分将如下所示,
蟒蛇3
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from downFiles.items import DownfilesItem
最后,要启用文件下载,我们需要对项目目录中的settings.py文件进行两个小的更改:
1. 启用文件下载:
ITEM_PIPELINES = {
'scrapy.pipelines.files.FilesPipeline': 1,
}
2. 在 settings.py 中指定下载的目标文件夹:
FILES_STORE = r"D:\scrapyProject\nirsoft\downloads"
注意:文件夹目的地应为实际目的地
我们使用原始字符串来避免由于 Windows 位置字符串的反斜杠引起的任何错误
现在如果我们运行
scrapy crawl nirsoft
我们将能够找到下载到指定目标文件夹的所有文件,这样我们就完成了!
限制要下载的文件类型
由于我们旨在下载实用程序的安装文件,因此最好将爬虫限制为仅下载 .zip 和 .exe 文件,而将其余文件排除在外。这也将减少抓取时间,从而使脚本更高效。
为此,我们需要编辑我们的 parse_items() 函数,如下所示:
蟒蛇3
def parse_item(self, response):
file_url = response.css('.downloadline::attr(href)').get()
file_url = response.urljoin(file_url)
file_extension = file_url.split('.')[-1]
if file_extension not in ('zip', 'exe', 'msi'):
return
item = DownfilesItem()
item['file_urls'] = [file_url]
item['original_file_name'] = file_url.split('/')[-1]
yield item
我们还需要将新的数据字段“original_file_name”添加到我们的项目类定义中:
蟒蛇3
class DownfilesItem(scrapy.Item):
# define the fields for your item here like:
file_urls = scrapy.Field()
original_file_name = scrapy.Field()
files = scrapy.Field
保存所有更改并运行,
scrapy crawl nirsoft
我们将能够找到下载到指定目标文件夹的所有 .zip 和 .exe 文件。但是,我们仍然有一个问题:
SHA1 哈希码不是人类可读的,因此最好使用它们的原始(人类可读)名称保存文件,这将引导我们进入下一部分
创建自定义管道
最初,我们使用 Scrapy 的默认管道来下载文件,但是,问题是文件使用其 SHA1 哈希码而不是人类可读的文件名保存。因此,我们需要创建一个自定义管道来保存原始文件名,然后在下载文件时使用该名称。
就像我们的项目类 (items.py) 一样,我们也有一个管道类 (pipelines.py),其中包含在我们创建项目时为我们的项目生成的类,我们将使用这个类来创建我们的自定义管道
蟒蛇3
from scrapy.pipelines.files import FilesPipeline
class DownfilesPipeline(FilesPipeline):
def file_path(self, request, response=None, info=None):
file_name: str = request.url.split("/")[-1]
return file_name
我们导入了 Scrapy 提供的默认 FilesPipeline,然后覆盖了 file_path函数,这样它就不会使用哈希码作为文件名,而是使用文件名。
我们注释掉了 process_item函数,以便它不会覆盖 FilesPipeline 中的默认 process_item函数。
接下来,我们更新我们的 settings.py 文件以使用我们的自定义管道而不是默认管道。
ITEM_PIPELINES = {
'downFiles.pipelines.DownfilesPipeline': 1,
}
最后,我们运行
scrapy crawl nirsoft
我们有我们的结果: