【Python】Scrapy爬虫网页分析入门实战

Scrapy 爬虫 网页分析入门实战

前言

刑啊,我们开始Python爬虫网页分析啦。由于某虫的叫法较为敏感(求生欲拉满),以下均将其称为网页分析吧!

说在前面
网页分析,是在实际工作中常见的需求之一,是通用的程序猿技能。我们多少都有必要掌握一些,这样在实际遇到这种需求时,可以快速上手。

本文基于对参考教程的学习,从脱敏示例的实战出发,直接演示Scrapy创建、网页分析、数据存储。篇幅有限,Scray简介、原理等概念,请读者自行查阅,本文和大家一起直接在实战中学习Scrapy如何使用。

学习目标

  • 会用 Python 进行简单的网页分析实战,将分析到的数据存储到mysql数据表

注意,使用网页分析技术,请严格遵守相关法律法规,本文仅供技术学习与交流,代码例子均为虚拟的脱敏示例。

1. 创建Scrapy项目

创建及运行Scrapy项目的前提是您的机器原本就有python环境,需要使用pip安装。

1.1 下载Scrapy

首先我们要在本地安装Scrapy。命令如下:

pip install scrapy

验证安装是否成功

scrapy version

若出现Scrapy 版本,例如我的是:Scrapy 2.11.1说明安装成功。

1.2 创建Scrapy项目

进入我们目标项目目录,执行

scrapy startproject <prject_name>

执行上述命令后,生成基础项目,里面包含了Scrapy项目的基本文件。

接下来,我们用pycharm等工具打开,然后需要注意一下是否设置了 python解释器。若没有设置,需要参考如下截图设置并生成.venv文件:
1

然后,在虚拟环境下再执行一遍:

pip install scrapy

这是为了在虚拟环境中也有scrapy相关依赖

1.3 创建Spider

terminal 执行 命令,参考如下:

scrapy genspider itcast "itcast.cn"

稍微解释一下,该命令的结构为:

scrapy genspider <spider_name> <domain>

domain为网站域名,意思为要分析的网站范围。后续的url都基于这个域名。要在实际业务使用的同学请将spider_name 和 domain 改成实际的。

那么此处我们就参照参考教程,爬取某客首页吧!

1.4 稍作修改并执行Demo

在上一小节执行了genspider命令后,项目里又增加了一些py文件。有点像脚手架。

我们稍作修改,将response保存为文件:

 def parse(self, response):
        filename = "test.html"
        open(filename, 'w').write(response.body)
        pass

执行一下:

scrapy crawl itcast

若成功在项目内生成test.html文件,至此scrapy项目创建与spider创建成功!

2. 获取Cookie

分析一些网站,需要获取Cookie。通常,获取Cookie往往是开始爬虫的第一步。这里介绍我自己常用的两种获取Cookie方式

2.1 urllib获取Cookie

urllib获取Cookie
urllib 的方式获取Cookie也是一种模拟登录。若初学的时候觉得Scrapy模拟登录的方式比较绕,略显复杂,可以用 urllib 模拟登录。当然,在模拟登录前,我们首先需要自己实际在浏览器登录一波,获取登录请求url、表单提交格式等。

示例代码如下:

# 模拟登录获取cookie
def get_cookie():
    cookie_list = []
    try:
    	# 使用的时候具体地址替换为实际的url
        url = "http://demo/url/login?xxx"
        # 表单可以用字典的形式提交,根据实际填写各key value
        data = {
            "key_word": "1",
            "password_secret": "08jsngalcoajv",
            "username/account": "demo_account",
            "password": "demo_password"
        }
        data = urllib.parse.urlencode(data).encode('utf-8')
        req = urllib.request.Request(url, data=data, method='POST')
        with urllib.request.urlopen(req) as response:
            # 获取响应头中的 Cookie
            cookies = response.headers.get('Set-Cookie')
            if cookies:
                cookie_list = cookies.split(', ')
            else:
                print("No cookies found in response headers")
    except Exception as e:
        print(e)
    result = get_result(cookie_list)
    cookies_dict = cookie_str_to_dict(result)
    return cookies_dict

# 根据格式处理cookie
def get_result(cookie_list):
    result = ""
    if cookie_list:
        # 拼接结果
        result = "; ".join(cookie.split(';')[0] for cookie in cookie_list)
    return result

# cookie进一步处理并以字典格式返回
def cookie_str_to_dict(cookie_str):
    cookie_dict = {}
    cookies = cookie_str.split('; ')
    for cookie in cookies:
        key, value = cookie.split('=')
        # 剔除部分不需要的cookie
        if key != "Path":
            cookie_dict[key] = value
    # 根据实际执行结果,手动补充一些固定值(可选)
    cookie_dict['acc'] = ''
    cookie_dict['use_type'] = 1
    return cookie_dict

另外,urllib的方式目前不支持微信、qq等登录。关于微信qq等第三方登录,需要另外想办法,这种登录方式后续再说。urllib支持表单填写post请求的方式。

start_requests携带Cookie
获取到cookie之后,接下来,就可以在具体scrapy xxx.py 里重写start_request方法,并携带cookie:

# 携带 cookie 直接访问目标页面
    def start_requests(self):
        cookies_dict = galaxy_governemnt_cookie.get_cookie()
        for url in self.start_urls:
            yield scrapy.Request(url, cookies=cookies_dict, callback=self.parse)

上述代码访问start_urls,并携带cookie,接着,回调函数指向parse方法,然后就可以愉快地在parse进行网页分析啦!

2.2 scrapy 模拟登录

我们也可以在scrapy的Spiders里进行模拟登录。登录后,再分析获取Cookie,之后,将Cookie带入下一步的请求,最后,再根据这个请求进行数据分析。

示例代码如下:

def start_requests(self):
        # 使用的时候具体地址替换为实际的url
        url = "http://demo/url/login?xxx"
        # 表单可以用字典的形式提交,根据实际填写各key value
        data = {
            "key_word": "1",
            "password_secret": "08jsngalcoajv",
            "username/account": "demo_account",
            "password": "demo_password"
        }
        yield scrapy.FormRequest(url, formdata=data, callback=self.parse)
        
def parse(self, response, *args, **kwargs):
	# 下一步操作,先从response里拿到Cookie信息,具体代码略.....
	pass

使用 Scrapy 进行模拟登录,建议使用 scrapy.FormRequest(url, formdata=data, [callback=<def_method>])来进行from表单的提交方式。

这种获取Cookie的方式在少量的爬虫项目里可以使用。若项目比较大,需要爬取的地方比较多,那么每次执行parse之前都要提交一次登录请求,这样整个项目难免会有部分代码冗余。这时候,就建议使用统一封装好的方法获取Cookie了。

3. 分析

具体网页分析需要2大步骤:数据建模与获取数据。

数据建模说白了就是定义一个类去接收获取到的数据,而获取数据时,需要我们有一定的xpath或CSS基础,通过xpath与选择器获取我们想要的数据了。

下面我们介绍具体分析的数据建模与获取数据步骤:

3.1 数据建模

数据建模需要我们在项目里 items.py 里新建一个类:

示例代码如下:

class DemoSpiderItem(scrapy.Item):
    # 代码
    code = scrapy.Field()
    # 使用类型
    use_type = scrapy.Field()
    # 使用编号
    use_num = scrapy.Field()

注意,这个类首先要继承scrapy.Item类,然后每个字段都要调用scrapy.Field()。语义上,这表示这个类的字段值都来自爬取的字段。
至于源码,我还没仔细研究,有兴趣的读者可以去研究一下。

3.2 获取数据

获取数据就在parse以及parse回调的方法里实现了。

我们直接看示例,假设我们要获取一个列表:

    def parse(self, response, *args, **kwargs):
        # 目标列表
        result_list = response.xpath('//*[@id="ec_table_body"]/tr')
        # 遍历列表,分析每一行元素
        for result in result_list:
            item = DemoSpiderItem()
            item['code'] = result.xpath('./tr[1]/td[3]').extract_first()
		   item['use_type'] = result.xpath('./tr[1]/td[3]').extract_first()
            yield item

通过示例,我们总结的流程是:分析要获取的页面元素xpath(或选择器),接着,用我们建模定义的数据去接收。

4. 管道

4.1 管道使用流程

Scrapy 框架已经帮我们将数据从爬虫逻辑中传输到管道。那么接下来的逻辑就在管道中处理即可。使用 Scrapy 管道主要有以下三步:创建管道、编写管道逻辑、开启管道。

下面我们逐一介绍。

4.1.1 创建管道

class GalaxyHnbcSpiderPipeline:
    # 定义用于接收 item 字典列表
    def __init__(self):
        self.item_list = []

    @staticmethod
    def open_spider(spider):
        if spider.name == "TestSpider":

    def process_item(self, item, spider):
        if spider.name == "TestSpider":
            # 将item转换为字典
            data = dict(item)
            # 将 data 加入 item_list
            self.item_list.append(data)
        return item
    def close_spider(self, spider):
        # 数据存储逻辑
        .....

创建管道主要通过spider名来判断具体执行哪个管道。其中,创建的管道主要有三部分:open_spider、process_item以及close_spider。

4.1.2 管道逻辑

管道的逻辑主要作数据处理,例如,什么数据插入,什么数据更新,要转换成什么类型等等。

4.1.3 开启管道

管道以及管道的逻辑编辑完成后,我们还要再settings.py开启管道。序号参数越小代表优先级越高,当前版本的Scrapy配置管道相关在settings.py的67行,序号默认为300,不建议序号超过1000:

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

4.2 持久化

有时,我们爬取的数据需要根据实际需求来进行存储,例如:为了保持数据业务的完整性、一致性,需要先将库里的数据对Scrapy爬取下来的数据进行一个对比,再进行持久化操作。

这里我采用SQLAlchemy连接数据库,在管道结束时将数据比对并插入数据库:

存储逻辑

def close_spider(self, spider):
    if spider.name == "TestSpider":
       spider_list = []
    for temp_dict in self.item_list:
          # 将主键的值设置为空
          temp_dict['pid'] = None
          demo_calss = DemoClass(temp_dict)
          spider_list.append(demo_calss)
		 # 数据存储逻辑
          if spider_list:
             with Session(db_init.engine) as session:
                  exist_list = session.query(GalaxyHnbc).all()
                  insert_list = spider_list
                  # 删除列表:数据库里有的,而爬虫结果没有的
                  delete_list = []
                  # 更新列表:爬虫结果和数据库里都有的,不管一不一样直接更新
                  update_list = []
                  # 执行新增
                  if insert_list:
                      session.add_all(insert_list)
                      session.commit()

SqlAlchemy
关于SqlAlchemy,是一种可选的持久化方式。当然读者也可以选择其它连接数据库的方式,将爬取的数据保存下来。

5. 补充与总结

5.1 Scrapy下载/创建过程中遇到的问题

本次我个人在Windows执行scrapy version时报错了,大家遇到的各种错误与原因都可能不相同,我本次遇到的问题参考以下解决方案自行解决:

  • https://blog.csdn.net/weixin_38708145/article/details/130219078
  • https://blog.csdn.net/yujinlong2002/article/details/126660363

5.2 分页/多级页面解决方案

当我们要分析的是分页/多级页面时,可以在start_requests方法里先进行页面的预处理,也就是说,先手动分析分页的参数,然后在start_requests方法里事先拼接好二级页面的url参数,然后再通过循环等方式请求,将具体的response交给parse方法解析。

如下示例:

    def start_requests(self):
        cookies_dict = target_website_cookie.get_cookie()
        # 二级页面初始url
        secondary_start_url = ("http://demo/url")

        # 定义 二级页面 url 所需参数 字典 数组
        secondary_params = []

        # 访问一级页面获取关键信息
        start_response = scrapy.Request(self.start_urls[0], cookies=cookies_dict)

        for element in start_response.xpath('//tr[onclick^=ECSideUtil.selectRow]'):
            tds = element.xpath('td')
            # 提取do_edit的参数
            secondary_id = tds[2].xpath('./input[@onclick]/@onclick').get().split("'")[1]
            # 提取其它信息
            review_status = tds[9].xpath('text()').get()
            # 将id和其它信息存入数组
            secondary_params.append({"secondary_id": secondary_id, "review_status": review_status})

        for secondary_param in secondary_params:
            # 拼接二级页面url
            secondary_url = secondary_start_url + secondary_param["secondary_id"]
            # 携带 cookie 直接访问目标页面
            yield scrapy.Request(secondary_url, cookies=cookies_dict, callback=self.parse, meta=secondary_param)

5.3 总结

本文主要基于个人的实际开发,总结了Scrapy的基本用法:

  • 项目配置、创建
  • Spider 网页分析的使用
  • 数据建模
  • 管道的使用
  • 数据持久化策略

感谢大家阅读此文,希望我的内容能够给您带来启发和帮助。如果您喜欢我的文章,欢迎点赞、评论和分享,让更多人看到。期待与您在下一篇文章再相会!

参考教程

  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值