安装
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple scrapy==2.11.2
创建工程
假设我要创建一个名叫 myspider
的 scrapy 工程,他的功能是爬取 url=https://baidu.com
的数据,需要运行以下命令:
# 创建工程文件夹并初始化整个scrapy工程
scrapy startproject myspider
# 进入工程文件夹
cd myspider
# 创建爬虫,语法如下: scrapy genspider 爬虫名称 需要爬的域名
scrapy genspider spider baidu.com
完成以上步骤之后,工程目录如下:
myspider
├── myspider
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-312.pyc
│ │ └── settings.cpython-312.pyc
│ ├── items.py
│ ├── middlewares.py
│ ├── pipelines.py
│ ├── settings.py
│ └── spiders
│ ├── __init__.py
│ ├── __pycache__
│ │ └── __init__.cpython-312.pyc
│ └── spider.py
└── scrapy.cfg
下面我们先来编写一个简单的案例,借此来说明这些文件如何配置使用
一个简单的工程
编写数据解析
首先打开 myspider/spiders/spider.py
,内容应该如下:
import scrapy
class SpiderSpider(scrapy.Spider):
name = "spider" # 爬虫名字,后面运行要用
allowed_domains = ["baidu.com"]
start_urls = ["https://baidu.com"]
def parse(self, response):
pass
我们需要修改 parse
函数,这里是对爬取页面的数据解析函数,假设在这里我通过 xpath 爬取百度首页的下图部分内容:
class SpiderSpider(scrapy.Spider):
name = "spider"
allowed_domains = ["baidu.com"]
start_urls = ["https://baidu.com"]
def parse(self, response):
a_list = response.xpath("//div[@class='s-top-left-new s-isindex-wrap']/a")[:8]
id = 0
for a in a_list:
text = a.xpath("./text()").extract_first()
text = text.strip()
dic = {
"id": id,
"text": text
}
id += 1
yield dic
在 pipelines.py
中打印结果:
class MyspiderPipeline:
def process_item(self, item, spider):
print(item)
return item
注意:
spider返回的内容只能是字典, requestes对象, item数据或者None. 其他内容一律报错
运行爬虫
# 运行爬虫美丽如下 scrapy crawl 爬虫名字
scrapy crawl spider
结果如下:
编写数据保存
在数据被抓去后,会传递到 pipeline,下面来看一下 pipeline 中如何处理数据:
首先要修改
settings.py
中的配置# 数据处理管道,这里可以填写多个 ITEM_PIPELINES = { "game.pipelines.GamePipeline": 300, "game.pipelines.MySQLPipeline": 300 }
在
pipelines.py
文件中编写数据存储代码,这里给出两个官方示例:# 存储到json import json from itemadapter import ItemAdapter class JsonWriterPipeline: def open_spider(self, spider): self.file = open("items.jsonl", "w") def close_spider(self, spider): self.file.close() def process_item(self, item, spider): line = json.dumps(ItemAdapter(item).asdict()) + "\n" self.file.write(line) return item
```python # 存储到Database import pymongo from itemadapter import ItemAdapter class MongoPipeline: collection_name = "scrapy_items" def __init__(self, mongo_uri, mongo_db): self.mongo_uri = mongo_uri self.mongo_db = mongo_db @classmethod def from_crawler(cls, crawler): return cls( mongo_uri=crawler.settings.get("MONGO_URI"), mongo_db=crawler.settings.get("MONGO_DATABASE", "items"), ) def open_spider(self, spider): self.client = pymongo.MongoClient(self.mongo_uri) self.db = self.client[self.mongo_db] def close_spider(self, spider): self.client.close() def process_item(self, item, spider): self.db[self.collection_name].insert_one(ItemAdapter(item).asdict()) return item
自定义数据传输结构 item
在上述案例中, 我们使用字典作为数据传递的载体, 但是如果数据量非常大. 由于字典的key是随意创建的. 极易出现问题, 此时再用字典就不合适了. Scrapy中提供item作为数据格式的声明位置. 我们可以在 items.py
文件提前定义好该爬虫在进行数据传输时的数据格式. 然后再写代码的时候就有了数据名称的依据了。
import scrapy
class MyspiderItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
pass
class BaiduItem(scrapy.Item):
id = scrapy.Field()
text = scrapy.Field()
在 spider.py
中运用如下:
import scrapy
from myspider.items import BaiduItem
class SpiderSpider(scrapy.Spider):
name = "spider"
allowed_domains = ["baidu.com"]
start_urls = ["https://baidu.com"]
def parse(self, response):
a_list = response.xpath("//div[@class='s-top-left-new s-isindex-wrap']/a")[:8]
id = 0
for a in a_list:
text = a.xpath("./text()").extract_first()
text = text.strip()
item = BaiduItem()
item["id"] = id
item["text"] = text
id += 1
yield item
两次运行结果一致:
评论