Scrapy学艺一:初次使用
1.安装卸载升级Scrapy
// 由于我的机器同时安装有Python2和Python3的pip,所以使用Python3的pip是需要输入pip3
// 安装
pip3 install Scrapy
// 卸载
pip3 uninstall Scrapy
// 升级
pip3 install --upgrade Scrapy
2.创建Scrapy项目
// projectName项目名称
scrapy startproject projectName
得到如下结构的文件夹:
projectName/
scrapy.cfg # 部署配置文件
projectName/ # 项目模块文件
__init__.py
items.py # 项目items文件
middlewares.py # 项目中间件文件
pipelines.py # 项目管道文件
settings.py # 项目设置文件
spiders/ # 具体的爬虫文件
__init__.py
3.第一个爬虫程序
爬虫程序需要写在spiders文件夹内,爬取的类需要继承自Spider类,并且需要指定爬取的url和如何解析数据。
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)
// 开始解析会调用该方法,方法内可以继续请求
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}')
4.运行爬虫
// 进入项目路径,输入
scrapy crawl quotes
Scrapy执行顺序:执行scrapy.Request->执行start_requests方法->获取到数据->执行parse方法。
5.可以通过设置属性的方式设置请求地址
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
// 将地址设置成属性
start_urls = [
'http://quotes.toscrape.com/page/1/',
'http://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)
6.使用Scrapy Shell
终端中输入:
scrapy shell http://www.baidu.com
即可打开了Scrapy Shell,我们可以在里面测试代码、测试数据返回等。
比如测试通过css获取有title节点的元素
// 返回的是Selector对象
response.css('title')
使用.getall()方法获取元素内容
// 返回的是title的文本内容
response.css('title::text').getall()
使用.get()方法获取首个节点
// 返回首个节点文本内容
response.css('title::text').get()
返回指定下标的内容
response.css('title::text')[1].get()
可以通过.re()方法,设置正则匹配规则,过滤数据,然后返回数据
response.css('title::text').re(r'Quotes.*')
可以在shell中输入view(response)
来查看获取到的数据信息。
当然,也可以使用XPath来获取节点
response.xpath('//title')
response.xpath('//title/text()').get()
作用同:
response.css('title')
response.css('title::text').get()
实际上,css获取的方式,在内部会转换成xpath来获取。
7.保存数据
可以看到,在parse方法内,通过yield生成了迭代器。运行爬虫,我们能看到有抓取到的数据打印。如果要把数据保存起来,运行爬虫的时候,可以这样:
scrapy crawl quotes -O quotes.json
Scrapy会将数据写入到quotes.json文件中。这种方式对小项目可行,大型项目的话,就需要用到管道了,在项目中位置项目名/pipelines.py
中。
8.继续爬取下一个网页
在parse方法中,我们解析到了下一个网页,那么,如何让Scrapy继续读取该网页呢,使用scrapy.Request()方法即可
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'http://quotes.toscrape.com/page/1/',
]
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').get(),
'author': quote.css('small.author::text').get(),
'tags': quote.css('div.tags a.tag::text').getall(),
}
next_page = response.css('li.next a::attr(href)').get()
if next_page is not None:
// response.urljoin()方法拼接出下一个url地址
next_page = response.urljoin(next_page)
// 我们可以设置下一个爬取的网页,同时指定解析的方法,然后通过yield构建成迭代器。
yield scrapy.Request(next_page, callback=self.parse)
使用scrapy.Request方法时,我们需要提供完整的url路径,如果使用response.follow()方法,则不需要我们拼接路径。
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'http://quotes.toscrape.com/page/1/',
]
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').get(),
'author': quote.css('span small::text').get(),
'tags': quote.css('div.tags a.tag::text').getall(),
}
next_page = response.css('li.next a::attr(href)').get()
if next_page is not None:
yield response.follow(next_page, callback=self.parse)
由于response.follow方法可传入Selector对象,可以可以改成下面这样:
for href in response.css('ul.pager a::attr(href)'):
yield response.follow(href, callback=self.parse)
同时,由于response.follow传入selector对象时,会自动使用href属性,所以可以继续修改:
for a in response.css('ul.pager a'):
yield response.follow(a, callback=self.parse)
如果是selector数组,则可以使用follow_all方法
anchors = response.css('ul.pager a')
yield from response.follow_all(anchors, callback=self.parse)
// 或者简写
yield from response.follow_all(css='ul.pager a', callback=self.parse)
9.附加参数
可以通过-a传递附加参数
scrapy crawl quotes -O quotes-humor.json -a tag=humor
其中该附加参数会传递给爬虫的init方法,同时会变成属性来使用。
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
def start_requests(self):
url = 'http://quotes.toscrape.com/'
// 获取附加参数tag
tag = getattr(self, 'tag', None)
if tag is not None:
url = url + 'tag/' + tag
yield scrapy.Request(url, self.parse)
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').get(),
'author': quote.css('small.author::text').get(),
}
next_page = response.css('li.next a::attr(href)').get()
if next_page is not None:
yield response.follow(next_page, self.parse)
这样,如果命令运行的时候,就可以指定tag来进行爬取。
10.总结
至此,Scrapy的初次使用完毕,总结一下,用起来还是非常方便的,我们不需要去处理数据请求,Scrapy会帮我们处理好,我们只需要关心数据的数据以及存储,相当的方便。