【python】

在PyCharm中创建Scrapy项目并爬取豆瓣电影Top 250数据

以下是从打开PyCharm开始的详细操作步骤:

1. 安装必要的软件

确保你已经安装了以下软件:

  • Python (建议版本3.6以上)
  • PyCharm
  • SQLite (可选,通常Python内置SQLite支持)
2. 打开PyCharm并创建一个新项目
  1. 打开PyCharm。
  2. 选择“Create New Project”。
  3. 在“Location”字段中,输入项目的路径,例如~/PycharmProjects/douban_scrapy
  4. 确保选中“New environment using”并选择“Virtualenv”。
  5. 选择Python解释器,建议使用Python 3.6以上版本。
  6. 点击“Create”创建项目。
3. 安装Scrapy
  1. 打开PyCharm的终端窗口(View > Tool Windows > Terminal)。
  2. 在终端中输入以下命令来安装Scrapy:
    pip install scrapy
    
4. 创建Scrapy项目
  1. 在PyCharm的终端中,导航到项目目录:
    cd ~/PycharmProjects/douban_scrapy
    
  2. 创建一个新的Scrapy项目:
    scrapy startproject douban
    
  3. Scrapy会在项目目录下创建一个名为douban的文件夹,其中包含Scrapy项目的基本结构。
5. 定义Item
  1. 打开douban/douban/items.py文件。
  2. 定义需要爬取的数据字段:
    import scrapy
    
    class MovieItem(scrapy.Item):
        rank = scrapy.Field()
        title = scrapy.Field()
        rating = scrapy.Field()
        num_reviews = scrapy.Field()
        quote = scrapy.Field()
        director = scrapy.Field()
        actors = scrapy.Field()
        region = scrapy.Field()
        genre = scrapy.Field()
        summary = scrapy.Field()
    
6. 编写Spider
  1. douban/douban/spiders目录下创建一个新的Python文件,命名为douban_spider.py
  2. 编写爬虫代码:
    import scrapy
    from douban.items import MovieItem
    
    class DoubanSpider(scrapy.Spider):
        name = "douban"
        allowed_domains = ["movie.douban.com"]
        start_urls = ["https://movie.douban.com/top250"]
    
        def parse(self, response):
            for movie in response.css('div.item'):
                item = MovieItem()
                item['rank'] = movie.css('div.pic em::text').get()
                item['title'] = movie.css('span.title::text').get()
                item['rating'] = movie.css('span.rating_num::text').get()
                item['num_reviews'] = movie.css('div.star span:last-child::text').re_first(r'(\d+)')
                item['quote'] = movie.css('span.inq::text').get()
                detail_url = movie.css('div.hd a::attr(href)').get()
                request = scrapy.Request(detail_url, callback=self.parse_details)
                request.meta['item'] = item
                yield request
    
            next_page = response.css('span.next a::attr(href)').get()
            if next_page:
                yield response.follow(next_page, self.parse)
    
        def parse_details(self, response):
            item = response.meta['item']
            item['director'] = response.css('a[rel="v:directedBy"]::text').get()
            item['actors'] = response.css('a[rel="v:starring"]::text').getall()
            item['region'] = response.xpath('//span[text()="制片国家/地区:"]/following-sibling::text()').get()
            item['genre'] = response.css('span[property="v:genre"]::text').getall()
            item['summary'] = response.css('span[property="v:summary"]::text').get().strip()
            yield item
    
7. 实现Pipeline
  1. 打开douban/douban/pipelines.py文件。
  2. 编写数据存储到SQLite的代码:
    import sqlite3
    
    class SQLitePipeline:
        def open_spider(self, spider):
            self.connection = sqlite3.connect("movies.db")
            self.cursor = self.connection.cursor()
            self.cursor.execute('''
                CREATE TABLE IF NOT EXISTS top250 (
                    rank INTEGER PRIMARY KEY,
                    title TEXT,
                    rating REAL,
                    num_reviews INTEGER,
                    quote TEXT,
                    director TEXT,
                    actors TEXT,
                    region TEXT,
                    genre TEXT,
                    summary TEXT
                )
            ''')
            self.connection.commit()
    
        def close_spider(self, spider):
            self.connection.close()
    
        def process_item(self, item, spider):
            self.cursor.execute('''
                INSERT OR REPLACE INTO top250 (rank, title, rating, num_reviews, quote, director, actors, region, genre, summary)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ''', (
                item['rank'],
                item['title'],
                item['rating'],
                item['num_reviews'],
                item['quote'],
                item['director'],
                ', '.join(item['actors']),
                item['region'],
                ', '.join(item['genre']),
                item['summary']
            ))
            self.connection.commit()
            return item
    
8. 配置Pipeline
  1. 打开douban/douban/settings.py文件。
  2. 添加Pipeline配置:
    ITEM_PIPELINES = {
       'douban.pipelines.SQLitePipeline': 300,
    }
    
9. 运行爬虫
  1. 打开PyCharm的终端窗口。
  2. 导航到项目目录:
    cd ~/PycharmProjects/douban_scrapy/douban
    
  3. 运行爬虫:
    scrapy crawl douban
    
  4. 确认数据已经被爬取并存储到SQLite数据库中。
10. 数据分析
  1. 在项目根目录下创建一个新的Python脚本,命名为data_analysis.py

  2. 编写数据分析脚本:

    import sqlite3
    import pandas as pd
    
    # 连接SQLite数据库
    conn = sqlite3.connect('movies.db')
    
    # 读取数据
    df = pd.read_sql_query("SELECT * FROM top250", conn)
    
    # 按制片国家/地区排名前十名的电影
    top_regions = df['region'].value_counts().head(10)
    print("按制片地区排名前十名的电影:")
    print(top_regions)
    
    # 按电影类型排名前十名的电影
    top_genres = df['genre'].str.split(', ').explode().value_counts().head(10)
    print("\n按电影类型排名前十名的电影:")
    print(top_genres)
    
    # 按评论人数排名前十名的电影
    top_reviews = df.sort_values(by='num_reviews', ascending=False).head(10)
    print("\n按评论人数排名前十名的电影:")
    print(top_reviews[['title', 'num_reviews']])
    
  3. 运行数据分析脚本:

    python data_analysis.py
    
11. 提交项目
  1. 确保所有代码已经完成并保存。
  2. 提交整个项目文件夹,包括movies.db数据库文件。
12. 编写实验报告
  1. 任务描述。
  2. 爬虫设计,包括选择和提取页面数据的方法、处理分页和详情页请求的方法、处理数据并存储到SQLite数据库的方法。
  3. 关键代码说明。
  4. 爬虫运行结果,包括部分爬取的数据示例。
  5. 数据分析结果。
  6. 实现过程中遇到的问题及解决方案。

【其他】 意外情况

修复 Scrapy 运行错误

这个错误通常与 Python 和 Scrapy 版本的兼容性有关。以下是修复此问题的几种方法:

方法 1: 修改 scrapy 配置文件
  1. 打开 douban/douban/settings.py 文件。
  2. 添加以下配置来使用 twistedreactor
    TWISTED_REACTOR = 'twisted.internet.asyncioreactor.AsyncioSelectorReactor'
    
方法 2: 升级 twisted

有时,这个问题是由 twisted 的版本引起的。可以尝试升级 twisted

  1. 打开 PyCharm 的终端窗口。
  2. 运行以下命令来升级 twisted
    pip install --upgrade twisted
    
方法 3: 使用适配器包

可以安装 scrapy 的适配器包 scrapy-reactor 来解决此问题:

  1. 打开 PyCharm 的终端窗口。

  2. 安装适配器包:

    pip install scrapy-reactor
    
  3. douban/douban/settings.py 文件中添加以下配置:

    REACTOR = 'scrapy_reactor.asyncioreactor.AsyncioSelectorReactor'
    
方法 4: 使用不同的 reactor

reactor 更改为 twisted.internet.selectreactor.SelectReactor 以避免异步问题:

  1. 打开 douban/douban/settings.py 文件。
  2. 添加以下配置来使用 SelectReactor
    from twisted.internet import selectreactor
    selectreactor.install()
    
检查其他设置

确保你的项目结构和配置正确无误。以下是配置 scrapy 项目的步骤回顾:

  1. 项目结构

    douban/
    ├── douban/
    │   ├── __init__.py
    │   ├── items.py
    │   ├── middlewares.py
    │   ├── pipelines.py
    │   ├── settings.py
    │   └── spiders/
    │       ├── __init__.py
    │       └── douban_spider.py
    ├── scrapy.cfg
    
  2. items.py

    import scrapy
    
    class MovieItem(scrapy.Item):
        rank = scrapy.Field()
        title = scrapy.Field()
        rating = scrapy.Field()
        num_reviews = scrapy.Field()
        quote = scrapy.Field()
        director = scrapy.Field()
        actors = scrapy.Field()
        region = scrapy.Field()
        genre = scrapy.Field()
        summary = scrapy.Field()
    
  3. douban_spider.py

    import scrapy
    from douban.items import MovieItem
    
    class DoubanSpider(scrapy.Spider):
        name = "douban"
        allowed_domains = ["movie.douban.com"]
        start_urls = ["https://movie.douban.com/top250"]
    
        def parse(self, response):
            for movie in response.css('div.item'):
                item = MovieItem()
                item['rank'] = movie.css('div.pic em::text').get()
                item['title'] = movie.css('span.title::text').get()
                item['rating'] = movie.css('span.rating_num::text').get()
                item['num_reviews'] = movie.css('div.star span:last-child::text').re_first(r'(\d+)')
                item['quote'] = movie.css('span.inq::text').get()
                detail_url = movie.css('div.hd a::attr(href)').get()
                request = scrapy.Request(detail_url, callback=self.parse_details)
                request.meta['item'] = item
                yield request
    
            next_page = response.css('span.next a::attr(href)').get()
            if next_page:
                yield response.follow(next_page, self.parse)
    
        def parse_details(self, response):
            item = response.meta['item']
            item['director'] = response.css('a[rel="v:directedBy"]::text').get()
            item['actors'] = response.css('a[rel="v:starring"]::text').getall()
            item['region'] = response.xpath('//span[text()="制片国家/地区:"]/following-sibling::text()').get()
            item['genre'] = response.css('span[property="v:genre"]::text').getall()
            item['summary'] = response.css('span[property="v:summary"]::text').get().strip()
            yield item
    
  4. pipelines.py

    import sqlite3
    
    class SQLitePipeline:
        def open_spider(self, spider):
            self.connection = sqlite3.connect("movies.db")
            self.cursor = self.connection.cursor()
            self.cursor.execute('''
                CREATE TABLE IF NOT EXISTS top250 (
                    rank INTEGER PRIMARY KEY,
                    title TEXT,
                    rating REAL,
                    num_reviews INTEGER,
                    quote TEXT,
                    director TEXT,
                    actors TEXT,
                    region TEXT,
                    genre TEXT,
                    summary TEXT
                )
            ''')
            self.connection.commit()
    
        def close_spider(self, spider):
            self.connection.close()
    
        def process_item(self, item, spider):
            self.cursor.execute('''
                INSERT OR REPLACE INTO top250 (rank, title, rating, num_reviews, quote, director, actors, region, genre, summary)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ''', (
                item['rank'],
                item['title'],
                item['rating'],
                item['num_reviews'],
                item['quote'],
                item['director'],
                ', '.join(item['actors']),
                item['region'],
                ', '.join(item['genre']),
                item['summary']
            ))
            self.connection.commit()
            return item
    
  5. settings.py

    BOT_NAME = 'douban'
    
    SPIDER_MODULES = ['douban.spiders']
    NEWSPIDER_MODULE = 'douban.spiders'
    
    ROBOTSTXT_OBEY = True
    
    ITEM_PIPELINES = {
       'douban.pipelines.SQLitePipeline': 300,
    }
    
    TWISTED_REACTOR = 'twisted.internet.asyncioreactor.AsyncioSelectorReactor'
    

通过上述方法,应该能够解决 reactor 的错误问题。如果问题仍然存在,请确保 Scrapy 和 Twisted 版本是最新的,并尝试在一个新的虚拟环境中重新安装这些库。

  • 17
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值