引言
Scrapy是一個用Python編寫的開源、功能強大的網絡爬蟲框架,專為網頁抓取和數據提取設計。它允許開發者高效地從網站上抓取所需的數據,并通過一系列可擴展和可配置的組件來處理這些數據。Scrapy框架的核心組成部分包括:
- Scrapy Engine(引擎): 負責控制數據流,協調各個組件之間的交互,實現爬蟲的邏輯。
- Scheduler(調度器): 負責管理待抓取的請求隊列,決定下一個要抓取的請求是什么。
- Downloader(下載器): 負責處理調度器傳來的請求,獲取網頁內容,并將其傳遞給Spider處理。
- Spiders(爬蟲): 自定義類,定義了如何解析下載回來的網頁內容,并提取結構化數據(Items)。每個Spider負責處理一個或一組特定的網站或頁面結構。
- Item Pipeline(項目管道): 數據處理的流水線,負責處理Spider提取的數據,進行清洗、驗證、去重、存儲等操作。每個項目經過一系列的Pipeline組件,直至處理完成。
- Middlewares(中間件): 分為請求/響應中間件和Spider中間件,位于引擎和其他組件之間,可以全局地處理請求、響應或改變數據流向,提供了高度的靈活性和可擴展性。
Scrapy的特點和優勢包括:
易于使用和部署: 提供了命令行工具簡化了項目的創建、運行和管理。
靈活性和可擴展性: 設計為高度模塊化,可以很容易地自定義或替換組件以滿足特定需求。
高性能: 基于Twisted異步網絡庫,支持并發下載,能夠高效處理大量請求。
廣泛的應用場景: 適用于數據挖掘、價格監控、市場研究、搜索引擎優化等領域。
Scrapy通過定義良好的API和組件模型,使得開發者能夠快速構建復雜的爬蟲,同時保持代碼的整潔和可維護性。
本篇文章參考b站視頻
【1小時學會爬取豆瓣熱門電影,快速上手Scrapy爬蟲框架,python爬蟲快速入門!】 https://www.bilibili.com/video/BV18a411777v/?share_source=copy_web&vd_source=70bc998418623a0cee8f4ac32d696e49
一、在命令窗口中使用命令創建一個scrapy項目
首先我們進行安裝有scrapy框架的虛擬環境下的scripts目錄下,用scrapy startproject項目名稱,來創建一個scrapy爬蟲項目。
在希望scrapy項目放置位置的文件夾下運行如下命令:
scrapy startproject douban_spider
在pycharm編輯器打開改項目,生成的項目結構如下:
二、在items.py文件中定義字段
這些字段用來臨時存儲我們要去抓取的結構化數據,方便后面保數據到其他地方,比如數據庫或者本地文本之類。
Item文件編寫
- Item是保存爬取到的數據的容器;其使用方法和Python字典類似,并且提供了額外保護機制來避免拼寫錯誤導致的未定義字段錯誤。
- 以豆瓣電影Top250 為例,我們需要抓取每一步電影的名字,電影的評分以及電影的評分人數。
- 豆瓣電影 Top 250 (douban.com)
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.htmlimport scrapyclass DoubanSpiderItem(scrapy.Item):# define the fields for your item here like:# name = scrapy.Field()title = scrapy.Field() # 電影名字star = scrapy.Field() # 評分critical = scrapy.Field() # 評分人數pass
三、在piplines.py中存儲自己的數據,我們在此存儲為csv格式
- 我們準備把分析提取出來的結構化數據存儲為csv格式。首先在piplines文件中創建一個類,在該類的構造函數中創建一個文件對象,然后在process_item函數中做數據存儲處理(編碼成utf-8格式),最后關閉文件。
piplines.py文件代碼如下:
class DoubanSpiderPipeline:def __init__(self):self.file = open("d:/douban.csv", "wb")def process_item(self, item, spider):str = item['title'].encode('utf-8') + b',' + item['star'].encode('utf-8') + b',' + item['critical'].encode('utf-8') + b'\n'self.file.write(str)return itemdef close_spider(self, spider):self.file.close()
四、爬蟲邏輯文件編寫
把每個文件都配置好之后,就可以自己寫一個邏輯處理文件,在spiders目錄下創建一個douban.py文件,在改文件中我們寫業務邏輯處理,主要是爬取,解析,把解析的內容結構化等等。
# encoding:utf-8
import scrapy
from scrapy.spiders import CrawlSpider
from scrapy.http import Request
from scrapy.selector import Selector
from douban_spider.items import DoubanSpiderItem# 定義一個類 繼承
class Douban(CrawlSpider):name = "douban" # 爬蟲項目名allowed_domains = ['douban.com'] # 爬取的域名start_urls = ['https://movie.douban.com/top250'] # 爬取的頁面網址# 請求是分布式的def start_requests(self):for url in self.start_urls:yield Request(url=url, callback=self.parse)def parse(self, response):item = DoubanSpiderItem()selector = Selector(response)Movies = selector.xpath('//div[@class="info"]')for eachMovie in Movies:title = eachMovie.xpath('div[@class="hd"]/a/span/text()').extract()[0]star = eachMovie.xpath('div[@class="bd"]/div/span[@class="rating_num"]/text()').extract()[0]critical = eachMovie.xpath('div[@class="bd"]/div/span/text()').extract()[1]item['title'] = titleitem['star'] = staritem['critical'] = criticalyield itemnextLink = selector.xpath('//span[@class="next"]/a/@href').get()# 確保nextLink有效且不是最后一頁if nextLink and 'javascript:void(0)' not in nextLink:# 注意處理相對路徑if not nextLink.startswith(('http:', 'https:')):nextLink = response.urljoin(nextLink)yield Request(url=nextLink, callback=self.parse)
運行程序
得到的csv文件如下:
*Settings文件編寫
- 該文件不是必須要編寫,我們完全可以把配置放在其他相應的文件中,比如headers放在頁面邏輯抓取文件中,文件或數據庫配置放在Pipeline文件中等等。
*如果需要轉存到數據庫方法
import csv
import mysql.connector
from mysql.connector import Error# MySQL數據庫連接參數
db_config = {'host': '127.0.0.1', # 數據庫主機地址'user': 'root', # 數據庫用戶名'password': '021211', # 數據庫密碼'database': 'douban' # 數據庫名稱
}# CSV文件路徑
csv_file_path = 'd:/douban.csv'try:# 連接到MySQL數據庫connection = mysql.connector.connect(**db_config)if connection.is_connected():db_info = connection.get_server_info()print(f"Successfully connected to MySQL Server version {db_info}")cursor = connection.cursor()columns = ["title", "star", "critical"] # 替換為你的列名# 讀取CSV文件并插入數據with open(csv_file_path, mode='r', encoding='utf-8') as file:csv_reader = csv.reader(file)next(csv_reader) for row in csv_reader:placeholders = ', '.join(['%s'] * len(row))query = f"INSERT INTO douban_spider ({', '.join(columns)}) VALUES ({placeholders})"cursor.execute(query, tuple(row))# 提交事務connection.commit()print(f"{cursor.rowcount} rows were inserted successfully.")except Error as e:print(f"Error while connecting to MySQL: {e}")
finally:# 關閉連接if connection.is_connected():cursor.close()connection.close()print("MySQL connection is closed.")