Scrapy爬虫框架

1. 定义

Scrapy是一个Python编写的开源网络爬虫框架,用于快速、高效地从网站中提取结构化的数据。它提供了一个完整的工具集,使得开发者可以轻松地构建和部署爬虫程序。

2. 组件

 

  1. 引擎(Engine):用来控制整个系统的数据处理流程
  2. Spiders(爬虫):定义了如何提取网站数据的规则,以及如何跟踪链接和处理页面。Spiders定义了起始URL、从页面中提取数据的方式以及如何跟踪链接等。

  3. Items(数据项):用于定义要抓取的数据结构,包含你所关心的数据字段。可以将网页中抓取的数据封装到Items对象中,方便进一步处理和存储。每个Item类似于一个字典,用于存储和提取特定的数据字段。

  4. Item Pipelines(数据管道):负责处理从爬虫中提取到的Item对象。通过定义一系列的Pipeline来对Item进行预处理、过滤、存储等操作,如数据清洗、去重、存储到数据库或文件等。

  5. Downloader(下载器):负责下载网页内容并返回给Spider处理。Scrapy内置了一个高效的下载器,可以通过设置不同的配置来实现多线程、代理、网页策略等功能。

  6. Scheduler(调度器):负责管理待抓取的URL队列,并根据一定的策略生成下一个要抓取的URL。Scrapy使用调度器来控制爬取流程,将请求分发给下载器,以便下载相应的网页内容。

  7. Middleware(中间件):提供了对Scrapy请求和响应的处理机制,可以在请求和响应的过程中注入自定义的操作。通过中间件,可以对发出的请求和得到的响应进行修改和处理。

3.安装和创建

3.1 安装

pip install scrapy

3.2创建scrapy项目

scrapy startproject 项目名

  • spiders文件夹专门用来放置爬虫程序,定义抓取特定网站的规则和逻辑,
  • items.py用来定义要提取和保存的数据结构,
  • pipelines.py用来处理数据,处理从爬虫提取的数据,如清洗、验证和存储等,
  • settings.py来进行各种设置,配置Scrapy框架和爬虫参数,
  • middlewares.py用来修改请求和响应的处理过程,如添加代理、设置User-Agent等。

cd 项目名

scrapy genspider 文件名 目标网站

3.3 爬取b站的数据

  • 项目目录

  • upinfo_spider.py
import scrapy
from scrapy.http import HtmlResponse

from bilibli_upinfo.items import UserBasicItem,UserOfficialItem,UserVipItem


class UpinfoSpider(scrapy.Spider):
    name = "upinfo_spider"
    allowed_domains = ["api.bilibili.com"]
    uuids = ["1899427463","268975831","478548672","510027392"]
    start_url = "https://api.bilibili.com/x/space/wbi/acc/info?mid=%(uuid)s"


    def start_requests(self):
        for userId in self.uuids:
            yield scrapy.Request(url=self.start_url%{"uuid":userId},dont_filter=True)

    def parse(self, response:HtmlResponse,**kwargs):
        up_data = response.json()['data']
        user_basic_item = UserBasicItem()
        user_basic_item['up_name'] = up_data['name']
        user_basic_item['up_mid'] = up_data['mid']
        user_basic_item['up_gender'] = up_data['sex']
        user_basic_item['up_avatar'] = up_data['face']
        user_basic_item['up_intro'] = up_data['sign']
        user_basic_item['up_level'] = up_data['level']
        user_basic_item['up_registered_time'] = up_data['jointime']
        user_basic_item['up_coins'] = up_data['coins']
        user_basic_item['up_login_log'] = up_data['fans_badge']
        user_basic_item['up_fans_medal'] = up_data['fans_medal']['show']

        user_official_item = UserOfficialItem()
        user_official_item['up_mid'] = up_data['mid']
        user_official_item['official_role'] = up_data['official']['role']
        user_official_item['official_title'] = up_data['official']['title']
        user_official_item['official_desc'] = up_data['official']['desc']
        user_official_item['official_type'] = up_data['official']['type']

        user_vip_item = UserVipItem()
        user_vip_item['up_mid'] = up_data['mid']
        user_vip_item['vip_type'] = up_data['vip']['type']
        user_vip_item['vip_status'] = up_data['vip']['status']
        user_vip_item['vip_due_date'] = up_data['vip']['due_date']
        user_vip_item['vip_pay_type'] = up_data['vip']['vip_pay_type']
        user_vip_item['vip_theme_type'] = up_data['vip']['theme_type']
        user_vip_item['vip_label_path'] = up_data['vip']['label']['path']
        user_vip_item['vip_label_text'] = up_data['vip']['label']['text']
        user_vip_item['vip_label_theme'] = up_data['vip']['label']['label_theme']
        user_vip_item['vip_label_text_color'] = up_data['vip']['label']['text_color']
        user_vip_item['vip_label_bg_style'] = up_data['vip']['label']['bg_style']
        user_vip_item['vip_label_bg_color'] = up_data['vip']['label']['bg_color']
        user_vip_item['vip_label_border_color'] = up_data['vip']['label']['border_color']
        user_vip_item['vip_label_use_img'] = up_data['vip']['label']['use_img_label']
        user_vip_item['vip_label_img_uri_hans'] = up_data['vip']['label']['img_label_uri_hans']
        user_vip_item['vip_label_img_uri_hant'] = up_data['vip']['label']['img_label_uri_hant']
        user_vip_item['vip_label_img_uri_hans_static'] = up_data['vip']['label']['img_label_uri_hans_static']
        user_vip_item['vip_label_img_uri_hant_static'] = up_data['vip']['label']['img_label_uri_hant_static']

        yield user_vip_item
        yield user_basic_item
        yield user_official_item
        # #用户基础信息表
        # print(f"UP主姓名:{up_name}")
        # print(f"UP主ID:{up_mid}")
        # print(f"UP主性别:{up_gender}")
        # print(f"UP主头像链接:{up_avatar}")
        # print(f"UP主简介:{up_intro}")
        # print(f"UP主等级:{up_level}")
        # print(f"UP主注册时间:{up_registered_time}")
        # print(f"UP主硬币数:{up_coins}")
        # print(f"UP主登录日志:{up_login_log}")
        # print(f"UP主粉丝勋章:{up_fans_medal}")
        #
        # #认证信息表
        # print(f"UP主ID:{up_mid}")
        # print(f"UP主官方认证信息:{official_role}")
        # print(f"UP主官方认证标题:{official_title}")
        # print(f"UP主官方认证描述:{official_desc}")
        # print(f"UP主官方认证类型:{official_type}")
        #
        # #会员信息表
        # print(f"UP主ID:{up_mid}")
        # print(f"UP主会员类型:{vip_type}")
        # print(f"UP主会员状态:{vip_status}")
        # print(f"UP主会员到期日期:{vip_due_date}")
        # print(f"UP主会员支付类型:{vip_pay_type}")
        # print(f"UP主会员主题类型:{vip_theme_type}")
        # print(f"UP主会员标签路径:{vip_label_path}")
        # print(f"UP主会员标签文本:{vip_label_text}")
        # print(f"UP主会员标签主题:{vip_label_theme}")
        # print(f"UP主会员标签文本颜色:{vip_label_text_color}")
        # print(f"UP主会员标签背景样式:{vip_label_bg_style}")
        # print(f"UP主会员标签背景颜色:{vip_label_bg_color}")
        # print(f"UP主会员标签边框颜色:{vip_label_border_color}")
        # print(f"UP主会员是否使用标签图片:{vip_label_use_img}")
        # print(f"UP主会员标签图片URI(简体中文):{vip_label_img_uri_hans}")
        # print(f"UP主会员标签图片URI(繁体中文):{vip_label_img_uri_hant}")
        # print(f"UP主会员标签图片URI(简体中文,静态):{vip_label_img_uri_hans_static}")
        # print(f"UP主会员标签图片URI(繁体中文,静态):{vip_label_img_uri_hant_static}")
  • items.py
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class UserBasicItem(scrapy.Item):
    up_name = scrapy.Field()
    up_mid = scrapy.Field()
    up_gender = scrapy.Field()
    up_avatar = scrapy.Field()
    up_intro = scrapy.Field()
    up_level = scrapy.Field()
    up_registered_time = scrapy.Field()
    up_coins = scrapy.Field()
    up_login_log = scrapy.Field()
    up_fans_medal = scrapy.Field()

class UserOfficialItem(scrapy.Item):
    up_mid = scrapy.Field()
    official_role = scrapy.Field()
    official_title = scrapy.Field()
    official_desc = scrapy.Field()
    official_type = scrapy.Field()

class UserVipItem(scrapy.Item):
    up_mid = scrapy.Field()
    vip_type = scrapy.Field()
    vip_status = scrapy.Field()
    vip_due_date = scrapy.Field()
    vip_pay_type = scrapy.Field()
    vip_theme_type = scrapy.Field()
    vip_label_path = scrapy.Field()
    vip_label_text = scrapy.Field()
    vip_label_theme = scrapy.Field()
    vip_label_text_color = scrapy.Field()
    vip_label_bg_style = scrapy.Field()
    vip_label_bg_color = scrapy.Field()
    vip_label_border_color = scrapy.Field()
    vip_label_use_img = scrapy.Field()
    vip_label_img_uri_hans = scrapy.Field()
    vip_label_img_uri_hant = scrapy.Field()
    vip_label_img_uri_hans_static = scrapy.Field()
    vip_label_img_uri_hant_static = scrapy.Field()

  • pipelines.py
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html


# useful for handling different item types with a single interface
from traceback import format_exc

import pymysql
from itemadapter import ItemAdapter
from scrapy.utils.project import get_project_settings

from bilibli_upinfo.items import UserBasicItem, UserOfficialItem, UserVipItem


class BilibliUpinfoPipeline:

    def __init__(self):
        # 获取MySQL配置
        mysql_host = get_project_settings().get('MYSQL_HOST')
        mysql_port = get_project_settings().get('MYSQL_PORT')
        mysql_database = get_project_settings().get('MYSQL_DATABASE')
        mysql_user = get_project_settings().get('MYSQL_USER')
        mysql_password = get_project_settings().get('MYSQL_PASSWORD')

        # 连接MySQL数据库
        self.connection = pymysql.connect(
            host=mysql_host,
            port=mysql_port,
            database=mysql_database,
            user=mysql_user,
            password=mysql_password,
            charset='utf8mb4',
            cursorclass=pymysql.cursors.DictCursor
        )

    def process_item(self, item, spider):
        try:
            if isinstance(item,UserBasicItem):
                # 处理用户基础信息表
                with self.connection.cursor() as cursor:
                    sql = '''
                    INSERT INTO user_basic_info (up_name, up_mid, up_gender, up_avatar, up_intro, up_level, up_registered_time,
                    up_coins, up_login_log, up_fans_medal)
                    VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                    '''
                    cursor.execute(sql, (
                        item['up_name'], item['up_mid'], item['up_gender'], item['up_avatar'], item['up_intro'],
                        item['up_level'],
                        item['up_registered_time'], item['up_coins'], item['up_login_log'], item['up_fans_medal']
                    ))
                    self.connection.commit()
            elif isinstance(item,UserOfficialItem):
                # 处理认证信息表
                with self.connection.cursor() as cursor:
                    sql = '''
                    INSERT INTO user_official_info (up_mid, official_role, official_title, official_desc, official_type)
                    VALUES (%s, %s, %s, %s, %s)
                    '''
                    cursor.execute(sql, (
                        item['up_mid'], item['official_role'], item['official_title'], item['official_desc'],
                        item['official_type']
                    ))
                    self.connection.commit()
            elif isinstance(item, UserVipItem):
                # 处理会员信息表
                with self.connection.cursor() as cursor:
                    sql = '''
                    INSERT INTO user_vip_info (up_mid, vip_type, vip_status, vip_due_date, vip_pay_type, vip_theme_type,
                    vip_label_path, vip_label_text, vip_label_theme, vip_label_text_color, vip_label_bg_style, vip_label_bg_color,
                    vip_label_border_color, vip_label_use_img, vip_label_img_uri_hans, vip_label_img_uri_hant,
                    vip_label_img_uri_hans_static, vip_label_img_uri_hant_static)
                    VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                    '''
                    cursor.execute(sql, (
                        item['up_mid'], item['vip_type'], item['vip_status'], item['vip_due_date'], item['vip_pay_type'],
                        item['vip_theme_type'], item['vip_label_path'], item['vip_label_text'], item['vip_label_theme'],
                        item['vip_label_text_color'], item['vip_label_bg_style'], item['vip_label_bg_color'],
                        item['vip_label_border_color'], item['vip_label_use_img'], item['vip_label_img_uri_hans'],
                        item['vip_label_img_uri_hant'], item['vip_label_img_uri_hans_static'],
                        item['vip_label_img_uri_hant_static']
                    ))
                    self.connection.commit()

        except:
            print(item)
            print(format_exc())

    def close_spider(self, spider):
        self.connection.close()
  • settings.py
# Override the default request headers:
DEFAULT_REQUEST_HEADERS = {  # 请求的头部
    'origin': "https://space.bilibili.com",
    'referer': "https://space.bilibili.com/",
    'user-agent': "*********自己的********",
    'Host': "api.bilibili.com"
}



# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   "bilibli_upinfo.pipelines.BilibliUpinfoPipeline": 300,
}

MYSQL_HOST = '127.0.0.1'  # 主机名
MYSQL_PORT = 3306  # 端口号
MYSQL_DATABASE = 'bilibili_users'  # 数据库名
MYSQL_USER = 'root'  # 用户名
MYSQL_PASSWORD = '123456'  # 密码


  • main.py


def run_cmd_Popen_fileno(cmd_string):
    """
    执行cmd命令,并得到执行后的返回值,python调试界面输出返回值
    :param cmd_string: cmd命令,如:'adb devices'
    :return:
    """
    import subprocess
    print('运行cmd指令:{}'.format(cmd_string))
    return subprocess.Popen(cmd_string, shell=True).wait()

if __name__ == '__main__':
    run_cmd_Popen_fileno("scrapy crawl upinfo_spider")
3.3.1 游标

在使用Python操作数据库时,使用游标(Cursor)是非常重要的。游标可以看作是与数据库直接交互的对象,通过游标可以执行SQL语句、获取执行结果等操作。

使用游标的主要原因是为了实现与数据库的交互和操作。通过游标,可以执行SQL语句对数据库进行不同的操作,如插入、查询、更新、删除等。游标还提供了获取查询结果和处理查询结果的方法,如fetchone()和fetchall()来获取查询结果的一行或多行数据。

具体原因如下:

  1. 执行多个SQL语句:游标可以执行多个SQL语句,执行的SQL语句可以是插入、更新、删除等操作。通过游标可以逐个执行这些操作,并将其提交到数据库中。

  2. 提交事务:数据库操作通常是在事务中进行的,事务是一个数据库操作序列,要么全部执行成功,要么全部执行失败。游标提供了commit()方法,可以将操作立即提交到数据库中。

  3. 获取执行结果:游标还可以获取执行SQL语句后的结果,如查询结果。通过使用fetchone()和fetchall()等方法,可以获取到查询结果的行数据或所有数据。

  4. 错误处理:通过游标可以捕获数据库操作的错误,如插入重复数据、数据插入长度超过限制等情况。异常处理可以帮助开发者快速定位问题,并做相应的处理。

总之,通过创建游标,可以更好地与数据库进行交互和操作,并能够获取执行结果和进行错误处理。这样可以有效地管理和控制对数据库的操作,确保数据的安全和完整性。

3.1.2 解析器

解析器是指用于解析和处理文档的工具或程序。在爬虫中,解析器主要用于解析网页内容,从中提取所需的数据。

常见的解析器包括XPath和CSS选择器。

  1. XPath:XPath是一种用于在XML或HTML文档中进行导航和提取数据的解析语言。它使用路径表达式来定位和选择节点,可以按照层级结构以及属性等进行筛选和定位。XPath可以通过节点名称、属性、文本内容等进行节点的定位,并提供丰富的函数和操作符用于节点的筛选和提取。在Scrapy中,使用XPath可以非常方便地从网页中提取所需的数据。

  2. CSS选择器:CSS选择器是一种通过样式选择器来筛选和选择节点的方式,常用于网页的样式设计。在爬虫中,可以借用CSS选择器来定位和提取网页中的元素。CSS选择器与XPath相比更简洁,容易理解和使用。Scrapy中也提供了对CSS选择器的支持,使得开发者可以根据CSS选择器来定位和提取数据。

解析器的选择取决于个人偏好和具体的应用场景。XPath和CSS选择器都是强大而灵活的工具,可以根据需求选择适合的解析器。在爬虫开发中,合理运用解析器能够更快地定位和提取所需的数据,提高爬虫的效率和准确性。

总结起来,这个完整的爬虫代码利用Scrapy框架实现了网页的下载、解析和数据提取,使用了XPath和CSS选择器来定位和提取所需的数据。通过自定义的中间件和Item Pipeline,实现了对请求和响应的处理以及数据的存储。这些关键技术的使用帮助实现了一个高效、可扩展的网络爬虫。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值