【笔记】Scrapy爬虫学习笔记(一)
之前一直使用requests和beautifulsoup来进行爬虫和脚本。最近毕业找工作,看了看爬虫工程师的岗位,发现有些要求熟悉scrapy和pyspider的框架,于是打算入坑学习一下,更新一下我的战术储备。这两天看了不少文档和教程,略微了解了这个框架,现在将我学习的笔记分享一下,希望能有用处!
# Scrapy学习笔记
## 什么是Scrapy?
> Scrapy是一个适用爬取网站数据、提取结构性数据的应用程序框架,它可以应用在广泛领域:Scrapy 常应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。通常我们可以很简单的通过 Scrapy 框架实现一个爬虫,抓取指定网站的内容或图片。
结构:
![结构](https://pic.rmb.bdstatic.com/bjh/down/d28e83db92e0e94adc238cb337d073c5.jpeg)
+ **Scrapy Engine(引擎)**:负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。
+ **Scheduler(调度器)**:它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
+ **Downloader(下载器)**:负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理。
+ **Spiders(爬虫)**:它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器)。
+ **Item Pipeline(管道)**:它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。
+ **Downloader Middlewares(下载中间件)**:一个可以自定义扩展下载功能的组件。
+ **Spider Middlewares(Spider中间件)**:一个可以自定扩展和操作引擎和Spider中间通信的功能组件。
**总结**:一个功能强大的爬虫框架:)接下来学习如何使用scrapy
## 安装
```bash
pip install Scrapy
```
## 一、创建项目
在终端输入:
```bash
scrapy startproject mySpider
```
生成的项目文件结构为:
```txt
mySpider/
scrapy.cfg
mySpider/
__init__.py
items.py
pipelines.py
settings.py
spiders/
__init__.py
...
```
其中,
- scrapy.cfg为项目的配置文件。
- mySpider/为项目的Python模块,将会从这里引用代码。
- mySpider/items.py为项目的目标文件。
- mySpider/pipelines.py为项目的管道文件。
- mySpider/settings.py为项目的设置文件。
- mySpider/spiders/为存储爬虫代码目录。
## 二、创建蜘蛛
创建项目后,我们需要创建蜘蛛来爬取内容
蜘蛛的代码储存在`mySpider/spiders/`目录下
可以自行在文件夹中创建蜘蛛文件,也可以通过命令行自动完成创建
```bash
cd mySpider# 进入根目录
scrapy genspider biquge "xbiquwx.la"# biquge为蜘蛛名称,"xbiquwx.la"为目标url
```
创建完成后,在`mySpider/spiders/`目录下生成`biquge.py`文件,其内容为:
```python
import scrapy
class BiqugeSpider(scrapy.Spider):
name = 'biquge'# 名称
allowed_domains = ['xbiquwx.la']# 允许运行的域
start_urls = ['http://xbiquwx.la/']# urls,该列表下的url将会依次进行请求
def parse(self, response):# 回调函数
pass
```
其中,`parse()`函数用于在每次迭代请求后处理响应
> 例1:对小说某章节进行内容提取,并写入txt
>
> ```python
> class BiqugeSpider(scrapy.Spider):
> name = 'biquge'
> allowed_domains = ['xbiquwx.la']
> start_urls = ['https://www.xbiquwx.la/26_26516/10289395.html']
>
> def parse(self, response):# 回调函数
> content = response.xpath('//*[@id="content"]').extract_first()# 通过xpath提取内容
> with open("result.txt", "w") as f:
> f.write(content)
> ```
## 三、运行蜘蛛
在根目录下运行:
```bash
scrapy crawl biquge
```
运行`例1`中的蜘蛛,在根目录下得到`result.txt`
## 四、数据提取
### 1、控制台提取
使用`shell`来调试数据
```bash
scrapy shell "https://www.xbiquwx.la/26_26516/10289395.html"
```
`shell`将请求该页面的代码,并开始调试
通过`response.css()`的方法来定位元素,并返回一个或多个选择器
> 例2:一些定位样式:
> ```bash
> >>> response.css("div.bottom")# 选择div标签下class="bottom"的元素
> >>> response.css(".bottom")# 选择所有class="bottom"的元素
> >>> response.css("#content")# 选择所有id="bottom"的元素
> ```
scrapy将返回一个列表用于储存选择器
```bash
>>> title = response.css("title")
>>> title_content = title.css("title::text").get()# '::'符号用于提取该元素下的特定属性,如'text''href'等
>>> title_content = title.css("::text").get()# 对于本元素下的属性,可以省略本元素标签
>>> title_content = title.css("br,::text").getall()# 选取多个元素,用','隔开,使用getall()方法提取
```
更简略的是,对于简单的元素,可以将上面的步骤合并起来:
```bash
>>> title = response.css("title::text").get()
>>> content = response.css("div#content").get()
```
### 2、代码提取
将上面的提取过程放在回调函数中:
```python
import scrapy
class BiqugeSpider(scrapy.Spider):
name = 'biquge'# 名称
allowed_domains = ['xbiquwx.la']# 允许运行的域
start_urls = ['https://www.xbiquwx.la/26_26516/10289395.html']# urls,该列表下的url将会依次进行请求
def parse(self, response):# 回调函数
for box in response.css('div.box_con'):
yield {
'content': box.css('div#content::text').getall(),
}
```
运行蜘蛛并将结果保存至json文件中:
```bash
scrapy crawl biquge -O result.json# 可以使用json、xml、csv、jl(json line)
```
## 五、管道处理
管道用于蜘蛛提取数据后,进行的数据处理和下载任务
管道定义在`piplines.py`文件中
```python
from itemadapter import ItemAdapter
class MyspiderPipeline:
def __init__(self):# 管道初始化时的方法
pass
def process_item(self, item, spider):# 管道处理数据的方法(necessary),输入参数为item
return item# 处理完毕后返回引擎 (necessary)
def open_spider(self, spider):# 蜘蛛开启时的方法
pass
def close_spider(self, spider):# 管道关闭时的方法
pass
```
## 附录 CSS选择器
| 选择器 | 示例 | 示例说明 |
| :--------------------- | --------------------- | --------------------------------------------------------- |
| class | .intro | 选择所有class="intro"的元素 |
| #id | #firstname | 选择所有id="firstname"的元素 |
| * | * | 选择所有元素 |
| element | p | 选择所有<p>元素 |
| element,element | div,p | 选择所有<div>元素和<p>元素 |
| elementelement | div p | 选择<div>元素内的所有<p>元素 |
| element>element | div>p | 选择所有父级是 <div> 元素的 <p> 元素 |
| element+element | div+p | 选择所有紧接着<div>元素之后的<p>元素 |
| | | 选择所有带有target属性元素 |
| | | 选择所有使用target="-blank"的元素 |
| | | 选择标题属性包含单词"flower"的所有元素 |
| | | 选择一个lang属性的起始值="EN"的所有元素 |
| :link | a:link | 选择所有未访问链接 |
| :visited | a:visited | 选择所有访问过的链接 |
| :active | a:active | 选择活动链接 |
| :hover | a:hover | 选择鼠标在链接上面时 |
| :focus | input:focus | 选择具有焦点的输入元素 |
| :first-letter | p:first-letter | 选择每一个<P>元素的第一个字母 |
| :first-line | p:first-line | 选择每一个<P>元素的第一行 |
| :first-child | p:first-child | 指定只有当<p>元素是其父级的第一个子级的样式。 |
| :before | p:before | 在每个<p>元素之前插入内容 |
| :after | p:after | 在每个<p>元素之后插入内容 |
| :lang(language) | p:lang(it) | 选择一个lang属性的起始值="it"的所有<p>元素 |
| element1~element2 | p~ul | 选择p元素之后的每一个ul元素 |
| | a | 选择每一个src属性的值以"https"开头的元素 |
| | a | 选择每一个src属性的值以".pdf"结尾的元素 |
| | a | 选择每一个src属性的值包含子字符串"runoob"的元素 |
| :first-of-type | p:first-of-type | 选择每个p元素是其父级的第一个p元素 |
| :last-of-type | p:last-of-type | 选择每个p元素是其父级的最后一个p元素 |
| :only-of-type | p:only-of-type | 选择每个p元素是其父级的唯一p元素 |
| :only-child | p:only-child | 选择每个p元素是其父级的唯一子元素 |
| :nth-child(n) | p:nth-child(2) | 选择每个p元素是其父级的第二个子元素 |
| :nth-last-child(n) | p:nth-last-child(2) | 选择每个p元素的是其父级的第二个子元素,从最后一个子项计数 |
| :nth-of-type(n) | p:nth-of-type(2) | 选择每个p元素是其父级的第二个p元素 |
| :nth-last-of-type(n) | p:nth-last-of-type(2) | 选择每个p元素的是其父级的第二个p元素,从最后一个子项计数|
| :last-child | p:last-child | 选择每个p元素是其父级的最后一个子级。 |
| :root | :root | 选择文档的根元素 |
| :empty | p:empty | 选择每个没有任何子级的p元素(包括文本节点) |
| :target | #news:target | 选择当前活动的#news元素(包含该锚名称的点击的URL) |
| :enabled | input:enabled | 选择每一个已启用的输入元素 |
| :disabled | input:disabled | 选择每一个禁用的输入元素 |
| :checked | input:checked | 选择每个选中的输入元素 |
| :not(selector) | :not(p) | 选择每个并非p元素的元素 |
| ::selection | ::selection | 匹配元素中被用户选中或处于高亮状态的部分 |
| :out-of-range | :out-of-range | 匹配值在指定区间之外的input元素 |
| :in-range | :in-range | 匹配值在指定区间之内的input元素 |
| :read-write | :read-write | 用于匹配可读及可写的元素 |
| :read-only | :read-only | 用于匹配设置 "readonly"(只读) 属性的元素 |
| :optional | :optional | 用于匹配可选的输入元素 |
| :required | :required | 用于匹配设置了 "required" 属性的元素 |
| :valid | :valid | 用于匹配输入值为合法的元素 |
| :invalid | :invalid | 用于匹配输入值为非法的元素 |
爬虫还是不要干了,自己玩还行,不要干这个工作,几年之后会后悔的,还是学其他的吧 bryanhan 发表于 2022-6-23 20:14
爬虫还是不要干了,自己玩还行,不要干这个工作,几年之后会后悔的,还是学其他的吧
谢谢指点!我今年打算考研,然后随便找个工作过度一下{:301_1008:} bryanhan 发表于 2022-6-23 20:14
爬虫还是不要干了,自己玩还行,不要干这个工作,几年之后会后悔的,还是学其他的吧
为什么几年后会后悔啊? wanderrr 发表于 2022-6-24 09:26
为什么几年后会后悔啊?
官方赠与银手镯一副,质保10年{:1_918:} 加油,有时候用得上的 有时候用得上的 学习了,有空练练
页:
[1]