admin 管理员组文章数量: 887021
文章目录
- scrapy简介
- 初尝scrapy
- 安装scrapy
- 第一个scrapy项目
- 创建项目
- 修改爬虫
- 运行爬虫
- 提取网页数据
- 可以把结果存储在json文件
- 后续
scrapy简介
按scrapy官网的介绍来说,scrapy是一种快速的高级web crawling和web scraping,用于对网站进行爬取并从其页面提取结构化数据的框架,也就是爬虫。它可以用于数据挖掘、数据监控和自动化测试。
初尝scrapy
安装scrapy
在有python环境下,可以直接使用pip安装。
pip install scrapy
安装完成后,直接在命令中输入scrapy验证是否安装成功,运行之后结果如下:
Scrapy 2.4.1 - no active project
Usage:
scrapy <command> [options] [args]
Available commands:
bench Run quick benchmark test
commands
fetch Fetch a URL using the Scrapy downloader
genspider Generate new spider using pre-defined templates
runspider Run a self-contained spider (without creating a project)
settings Get settings values
shell Interactive scraping console
startproject Create new project
version Print Scrapy version
view Open URL in browser, as seen by Scrapy
[ more ] More commands available when run from project directory
Use "scrapy <command> -h" to see more info about a command
默认情况下,会直接弹出可运行的命令。
第一个scrapy项目
创建项目
创建一个scrapy项目,在命令行中输入以下命令下,则会在当前目录下生成scr_first项目,这是一个python项目,可以使用IDE打开。
scrapy startproject hello_scrapy
创建好项目后,然后进入到hello_scrapy目录下,看下当前的目录结构:
├── hello_scrapy
│ ├── __init__.py
│ ├── items.py
│ ├── middlewares.py
│ ├── pipelines.py
│ ├── settings.py
│ └── spiders
│ └── __init__.py
└── scrapy.cfg
2 directories, 7 files
创建好项目后,接着我们创建一个db_book爬虫
scrapy genspider -t basic db_book douban
以上命令的意思就是说使用basic模版创建一个名为db_book,域名为douban的爬虫。
创建成功后,有如下提示:
Created spider 'db_book' using template 'basic' in module:
hello_scrapy.spiders.db_book
现在我们再来看看当前的目录结构:
├── hello_scrapy
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-37.pyc
│ │ └── settings.cpython-37.pyc
│ ├── items.py
│ ├── middlewares.py
│ ├── pipelines.py
│ ├── settings.py
│ └── spiders
│ ├── __init__.py
│ ├── __pycache__
│ │ └── __init__.cpython-37.pyc
│ └── db_book.py
└── scrapy.cfg
4 directories, 11 files
通过创建爬虫db_book前后对比,可以发现新增了几个文件,其中核心的文件在./spiders/db_book.py,这个是使用命令工具生成的名为db_book的爬虫。
修改爬虫
新建好项目和爬虫后,我们打开项目中的db_book爬虫,定义其具体的操作,该文件在hello_scrapy/spiders/db_book.py,打开db_book.py文件,默认情况下会定义了一个Book类,类里面默认重写parse方法,这个方法就是爬虫实际的解析操作方法。
import scrapy
class DbBookSpider(scrapy.Spider):
name = 'db_book'
allowed_domains = ['douban']
start_urls = ['http://douban/']
def parse(self, response):
pass
这里需要注意下start_urls字段,这个字段的意思就是爬虫开始的入口地址,我们这里爬取豆瓣读书编程类目看下,所以这里进行调整。调整后代码如下:
import scrapy
class DbBookSpider(scrapy.Spider):
name = 'db_book'
allowed_domains = ['douban']
start_urls = ['https://book.douban/tag/%E7%BC%96%E7%A8%8B']
def parse(self, response):
pass
在这里,我们为了快速验证爬虫的操作,我们直接保存爬取到的数据,在这里,可以直接修改parse方法,修改如下:
def parse(self, response):
file_name = 'douban_python'
with open(file_name,'wb') as f:
f.write(response.body)
运行爬虫
现在已经修改好了爬虫,那我们怎么运行它?
在命令行下,我们进入到项目根目录,在这里是:
/Users/michaelkoo/work/env/csdn/code/hello_scrapy
这里是刚刚我们新建的爬虫根目录,在根目录下,我们使用如下命令运行爬虫:
scrapy crawl db_book
运行之后,我们会看到类似下面的字眼:
2021-02-20 10:28:23 [scrapy.utils.log] INFO: Scrapy 2.4.1 started (bot: hello_scrapy)
2021-02-20 10:28:23 [scrapy.utils.log] INFO: Versions: lxml 4.6.2.0, libxml2 2.9.10, cssselect 1.1.0, parsel 1.6.0, w3lib 1.22.0, Twisted 20.3.0, Python 3.7.3 (default, Dec 13 2019, 19:58:14) - [Clang 11.0.0 (clang-1100.0.33.17)], pyOpenSSL 20.0.1 (OpenSSL 1.1.1i 8 Dec 2020), cryptography 3.3.1, Platform Darwin-19.6.0-x86_64-i386-64bit
2021-02-20 10:28:23 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.selectreactor.SelectReactor
2021-02-20 10:28:23 [scrapy.crawler] INFO: Overridden settings:
{'BOT_NAME': 'hello_scrapy',
'NEWSPIDER_MODULE': 'hello_scrapy.spiders',
'ROBOTSTXT_OBEY': True,
'SPIDER_MODULES': ['hello_scrapy.spiders']}
...
...
...
2021-02-20 10:28:25 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/exception_count': 1,
'downloader/exception_type_count/scrapy.exceptions.IgnoreRequest': 1,
'downloader/request_bytes': 227,
'downloader/request_count': 1,
'downloader/request_method_count/GET': 1,
'downloader/response_bytes': 536,
'downloader/response_count': 1,
'downloader/response_status_count/200': 1,
'elapsed_time_seconds': 1.490386,
'finish_reason': 'finished',
'finish_time': datetime.datetime(2021, 2, 20, 2, 28, 25, 451064),
'log_count/DEBUG': 2,
'log_count/INFO': 10,
'memusage/max': 50585600,
'memusage/startup': 50585600,
'response_received_count': 1,
'robotstxt/forbidden': 1,
'robotstxt/request_count': 1,
'robotstxt/response_count': 1,
'robotstxt/response_status_count/200': 1,
'scheduler/dequeued': 1,
'scheduler/dequeued/memory': 1,
'scheduler/enqueued': 1,
'scheduler/enqueued/memory': 1,
'start_time': datetime.datetime(2021, 2, 20, 2, 28, 23, 960678)}
2021-02-20 10:28:25 [scrapy.core.engine] INFO: Spider closed (finished)
注意,如果出现以下类似字眼,则需要修改下配置,
2021-02-20 15:31:31 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023
2021-02-20 15:31:31 [scrapy.core.engine] DEBUG: Crawled (403) <GET https://book.douban/robots.txt> (referer: None)
2021-02-20 15:31:31 [scrapy.core.engine] DEBUG: Crawled (403) <GET https://book.douban/tag/%E7%BC%96%E7%A8%8B> (referer: None)
2021-02-20 15:31:31 [scrapy.spidermiddlewares.httperror] INFO: Ignoring response <403 https://book.douban/tag/%E7%BC%96%E7%A8%8B>: HTTP status code is not handled or not allowed
打开setting.py文件,取消USER_AGENT的注释,并修改其内容,修改类似如下:
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_7) AppleWebKit/601.1 (KHTML, like Gecko) Version/13.1.3 Safari/601.1'
然后再次运行,即可看到以下类似字眼:
2021-02-20 15:33:22 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://book.douban/robots.txt> (referer: None)
2021-02-20 15:33:23 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://book.douban/tag/%E7%BC%96%E7%A8%8B> (referer: None)
2021-02-20 15:33:23 [scrapy.core.engine] INFO: Closing spider (finished)
代表已经抓取成功。
再看对应目录下,已经保存了对应的内容。
michaelkoo@MacBook hello_scrapy % ls
douban_python.html hello_scrapy scrapy.cfg
目前为止,已经抓取到对应网页的内容了。
提取网页数据
在前面,我们只是简单保存数据,并没有实际的进行数据提取,那么我们现在来看看如何提取数据。
- scrapy中,本身提供了一个类似调试模式的窗口,比如,使用shell工具,在命令行中,使用以下命令即可进入调试模式:
scrapy shell https://book.douban/tag/%E7%BC%96%E7%A8%8B
成功进入之后,会有对应的提示:
2021-02-20 15:39:13 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://book.douban/tag/%E7%BC%96%E7%A8%8B> (referer: None)
[s] Available Scrapy objects:
[s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s] crawler <scrapy.crawler.Crawler object at 0x108cb6128>
[s] item {}
[s] request <GET https://book.douban/tag/%E7%BC%96%E7%A8%8B>
[s] response <200 https://book.douban/tag/%E7%BC%96%E7%A8%8B>
[s] settings <scrapy.settings.Settings object at 0x108ca9d68>
[s] spider <DbBookSpider 'db_book' at 0x108e95860>
[s] Useful shortcuts:
[s] fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s] fetch(req) Fetch a scrapy.Request and update local objects
[s] shelp() Shell help (print this help)
[s] view(response) View response in a browser
这个时候,我们就可以单步调试,逐步提取我们需要的内容。
- 分析网页数据结构,获取所有节点
通过分析网页结构可以知道,每本书的节点都是在li标签下,并且有subject-item的class,因此我们目前就可以获取到所有节点。调试如下:
items = response.css('li.subject-item')
items[0] # 查看第一个数据内容
- 获取节点中的子节点
通过分析subject-item中的数据可知,每个item下面有个div,包含了书本的内容,其他div的class内容是info,依次,我们可以调试如下:
info = items[0].css('div.info')
title = info.css('a::text').get() # 主标题
sub_title = info.css('span::text').get() # 副标题
pub = info.css('div.pub::text').get() # 出版信息
rating = info.css('span.rating_nums::text').get()
pl = info.css('span.pl::text').get() # 评价
desp = info.css('p::text').get() # 描述
以上调试中,“::text”是表示获取内容的意思。
图片获取如下:
pic_div = item.css('div.pic')
pic = pic_div.css('img::attr(src)').get()
以上调试中的”::attr(src)“,表示获取属性src的内容。
- 现在我们来看看如何获取下一页的内容
从网页数据结构中,我们可以知道,下一页(后页)的内容在于class内容为next的span节点中,其父节点为class内容为paginator的div下面,调试如下:
paginator = response.css('div.paginator')
next = paginator.css('span.next').css('a::attr(href)').get()
- 编写爬虫实现
import scrapy
from scrapy.http.response.html import HtmlResponse
class DbBookSpider(scrapy.Spider):
name = 'db_book'
allowed_domains = ['douban']
start_urls = ['https://book.douban/tag/%E7%BC%96%E7%A8%8B']
def parse(self, response: HtmlResponse):
for item in response.css('li.subject-item'):
info = item.css('div.info')
title = info.css('a::text').get() # 主标题
sub_title = info.css('span::text').get() # 副标题
pub = info.css('div.pub::text').get() # 出版信息
rating = info.css('span.rating_nums::text').get()
pl = info.css('span.pl::text').get() # 评价
description = info.css('p::text').get() # 描述
pic_div = item.css('div.pic')
pic = pic_div.css('img::attr(src)').get()
yield {
'title': title,
'sub_title': sub_title,
'pub': pub,
'rating': rating,
'pl': pl,
'description': description,
'pic': pic
}
paginator = response.css('div.paginator')
next_page = paginator.css('span.next').css('a::attr(href)').get()
if next_page is not None:
yield response.follow(next_page, callback=self.parse)
可以把结果存储在json文件
如果需要把提取结果保存在json文件中,则可以在命令行中输入以下命令:
scrapy crawl db_book -O db_book.json
以下是抓取结果的统计:
2021-02-20 17:29:19 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 22533,
'downloader/request_count': 52,
'downloader/request_method_count/GET': 52,
'downloader/response_bytes': 671738,
'downloader/response_count': 52,
'downloader/response_status_count/200': 52,
'elapsed_time_seconds': 52.904263,
'finish_reason': 'finished',
'finish_time': datetime.datetime(2021, 2, 20, 9, 29, 19, 530091),
'item_scraped_count': 1000,
'log_count/DEBUG': 1052,
'log_count/INFO': 11,
'memusage/max': 50323456,
'memusage/startup': 50323456,
'request_depth_max': 50,
'response_received_count': 52,
'robotstxt/request_count': 1,
'robotstxt/response_count': 1,
'robotstxt/response_status_count/200': 1,
'scheduler/dequeued': 51,
'scheduler/dequeued/memory': 51,
'scheduler/enqueued': 51,
'scheduler/enqueued/memory': 51,
'start_time': datetime.datetime(2021, 2, 20, 9, 28, 26, 625828)}
另外,我们看看db_book.json文件的数据
[
{"title": "\n\n Python\u7f16\u7a0b\n\n\n \n ", "sub_title": " : \u4ece\u5165\u95e8\u5230\u5b9e\u8df5 ", "pub": "\n \n \n [\u7f8e] \u57c3\u91cc\u514b\u00b7\u9a6c\u745f\u65af / \u8881\u56fd\u5fe0 / \u4eba\u6c11\u90ae\u7535\u51fa\u7248\u793e / 2016-7-1 / 89.00\u5143\n\n ", "rating": "9.1", "pl": "\n (3559\u4eba\u8bc4\u4ef7)\n ", "description": "\u672c\u4e66\u662f\u4e00\u672c\u9488\u5bf9\u6240\u6709\u5c42\u6b21\u7684Python \u8bfb\u8005\u800c\u4f5c\u7684Python \u5165\u95e8\u4e66\u3002\u5168\u4e66\u5206\u4e24\u90e8\u5206\uff1a\u7b2c\u4e00\u90e8\u5206\u4ecb\u7ecd\u7528Python \u7f16\u7a0b\u6240\u5fc5\u987b\u4e86\u89e3\u7684\u57fa\u672c\u6982\u5ff5\uff0c\u5305\u62ecmatplot... ", "pic": "https://img9.doubanio/view/subject/s/public/s28891775.jpg"},
由于数据太多,我们在这里只是截取了其中一部分来看看格式化好的数据:
[{
"title": "\n\n Python编程\n\n\n \n ",
"sub_title": " : 从入门到实践 ",
"pub": "\n \n \n [美] 埃里克·马瑟斯 / 袁国忠 / 人民邮电出版社 / 2016-7-1 / 89.00元\n\n ",
"rating": "9.1",
"pl": "\n (3559人评价)\n ",
"description": "本书是一本针对所有层次的Python 读者而作的Python 入门书。全书分两部分:第一部分介绍用Python 编程所必须了解的基本概念,包括matplot... ",
"pic": "https://img9.doubanio/view/subject/s/public/s28891775.jpg"
},
{
"title": "\n\n 编码\n\n\n \n ",
"sub_title": " : 隐匿在计算机软硬件背后的语言 ",
"pub": "\n \n \n [美] Charles Petzold / 左飞、薛佟佟 / 电子工业出版社 / 2010 / 55.00元\n\n ",
"rating": "9.3",
"pl": "\n (3659人评价)\n ",
"description": "本书讲述的是计算机工作原理。作者用丰富的想象和清晰的笔墨将看似繁杂的理论阐述得通俗易懂,你丝毫不会感到枯燥和生硬。更重要的是,你会因此而获得对计算机工作原理... ",
"pic": "https://img2.doubanio/view/subject/s/public/s27331702.jpg"
}
]
看起来不是很完善,但好在基本的数据全部都有了。
后续
从以上结果可以看出,到这一步,基本是实现了从抓取、分析到存储到全部步骤,从上面的实例中,我们完全可以了解了scrapy的功能。至于其他更高级的功能,咱们可以根据后续文章看看。
版权声明:本文标题:python scrapy实践-爬取豆瓣读书 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1726436714h960361.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论