一、安装Scrapy框架
pip install scrapy
二、 创建scrapy框架默认目录
scrapy startproject tutorial
#tutorial为你的项目的名称
该炒作会为您自动创建项目目录
三、项目目录介绍
tutorial/ scrapy.cfg # deploy configuration file tutorial/ # project's Python module, you'll import your code from here __init__.py items.py # project items definition file middlewares.py # project middlewares file pipelines.py # project pipelines file settings.py # project settings file spiders/ # a directory where you'll later put your spiders __init__.py
四、先从第一只爬虫开始吧
爬虫用来定义爬取网站和相应结果处理是在Spider类定义的初始请求,我们开始第一次爬取数据新建一个文件在 tutorial/spiders
下的quotes_spider.py
import scrapy
class QuotesSpider(scrapy.Spider):
#标记爬虫程序,他在项目是唯一的,不同的爬行器用不同的名称
name = "quotes"
#该方法必须返回一个请求的可迭代数据,爬虫会从第一个数据开始爬取
def start_requests(self):
urls = [
'http://quotes.toscrape.com/page/1/',
'http://quotes.toscrape.com/page/2/',
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
#在每一个请求成功后处理相应数据的方法Response参数是 TextResponse 它保存页面内容
def parse(self, response):
page = response.url.split("/")[-2]
filename = f'quotes-{page}.html'
with open(filename, 'wb') as f:
f.write(response.body)
self.log(f'Saved file {filename}')
如何运行我们的爬虫代码呢?
跳转到项目顶级目录下运行:
scrapy crawl quotes
#quotes为爬虫文件的名称
代码会生成两个文件,类似于这样:、
这种方式可能不是那么快捷,有些操作是没有必要的,我们可以直接这样写
from pathlib import Path
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
#变量名为start_urls 会默认实现start_requests方法,无需书写该方法
start_urls = [
"https://quotes.toscrape.com/page/1/",
"https://quotes.toscrape.com/page/2/",
]
def parse(self, response):
page = response.url.split("/")[-2]
filename = f"quotes-{page}.html"
with open(filename, 'wb') as f:
f.write(response.body)
个人理解就是省却了写一个方法通过命名变量的方式来默认实现 start_urls 方法
五、提取数据
最好的学习方式是使用shell进行学习
在终端上运行:
scrapy shell "http://quotes.toscrape.com/page/1/"
你可以看到这样的结果:
你可以尝试筛选响应的对象:
response.css('title')
#该操作为使用scrapy库里的CSS选择器来筛选数据
执行之后你可以看到这样的响应
[<Selector query='descendant-or-self::title' data='<title>Quotes to Scrape</title>'>]
#这个操作代表获取到了一个HTML中的 <title> 标签,内容为 Quotes to Scrape
#Scrapy 返回的是一个包含 Selector 对象的列表
那么怎么提取其中的文本呢?
response.css('title::text').getall()
结果为:
['Quotes to Scrape']
即 ::text会筛选出title标题中的数据,如果我们不指定text那么会获取到完整的title标签:
>>> response.css('title').getall()
['<title>Quotes to Scrape</title>']
同时值得你注意的是,getall()返回的数据是一个列表,如果你只要返回一个数据可以
>>> response.css('title').get()
'<title>Quotes to Scrape</title>'
同时也可以有替代写法:
>>> response.css('title')[0].get()
'<title>Quotes to Scrape</title>'