爬虫爬 JSON HTML 数据

linong

最近这两周在忙着给公司爬一点数据,更文的速度有一点下降,预计今天就爬完了,总结总结经验。

其实之前我司是有专门做爬虫的,不用前端这边出人干活。后来那人离职了,有可能就没有爬虫这方面的需求了。突然又有了一些,前端这边出人做一下。老大说用 py 做,前期先调研一下。

原理

爬虫其实原理上很简单,我们==客户端他们==服务端
客户端发送请求 req,服务端返回响应 rsp。拿到响应之后解析数据,入库,就完事了。

请求数据 req

一般来说请求分为两种,拉数据 get 比较多。
偶尔部分接口需要登录,那就是多带 cookie 或者 headers
其实还有一部分工作就是分析入参

  1. get
    参数拼接在 url
  2. post
    参数放在 body

响应数据 rsp

返回数据大体上是两种

  1. JSON
    一般来说,通过 抓包 或者说 network 工具。我们找到了服务端的接口,那么我直接访问这个接口即可。
    本文第一个重点来了:切换到移动端再查一遍,往往有不一样的收获,一般来说 PCM 端的进度不了,有可能都不是一个项目组,所以实现方式就会有差别。
  2. html
    比较坑的一种方式,因为没有找到 JSON 接口。无奈只能走解析 HTML 的路子。

调研

  1. Node
    之前给后台搭架子的时候使用过,主要功能点如下:

    1. 自动登录,(拿headers、cookie
    2. 存储本地,每次请求带上 token
    3. 启动代理服务
  2. py 老大说要用这个东西。咨询了一下其他朋友,说可以使用下面的工具。

    1. requests + beautifulSoup
      使用起来其实就是 requests 发请求, beautifulSoup 解析 HTML。比较原始。
    2. scrapy
      一个爬虫的框架。我在这里学的 www.scrapyd.cn。实现上比较完整,可以设置请求间隔,随机 ua 等功能。
  3. 前端实现
    我一个铁头娃,怎么能轻言放弃?身为一个前端er,还是这些 api 让我更加亲切

    1. XHR
      发请求利器,打开对方页面,cookie 啥的都自带。无敌就是这么寂寞
      其实还可以找到对方请求发起的位置,打个断点,把对方内部的代码绑定到全局,这样一些内部逻辑什么的也都没问题。
      而且还 JSON HTML 通吃。
    2. iframe
      针对 HTML 类型的处理。同域的情况下,也无敌好吗?

      1. HTML 获取 DOM 节点?
      2. 甚至可以取 window 上的对象。vue SSR 你感觉到了威胁吗?
  4. 网上其他服务商提供的接口(真香啊)。有免费的有收费的,一般免费的限量。

    1. 比如抖音热度?
    2. 比如各类音乐的歌单和作品?
    3. IP 查询
    4. 天气查询

好了上面说了那么多,建议老大限制,我选择了 scrapy

scrapy

scrapy 是一个网页爬虫框架,神马叫做爬虫,如果没听说过,那就:内事不知问度娘,外事不决问谷歌,百度或谷歌一下吧!……(这里的省略号代表 scrapy 很牛逼,基本神马都能爬,包括你喜欢的苍老师……这里就不翻译了)

看到这个骚的飞起的介绍了吗?没错,我就是在上面学的。scrapy 中文站。接下来我就介绍一下我认为对于新手比较关注的东西

scrapy HTML

scrapy 处理器中的 response 标识你拿到的 rsp 上面自带了一些方法,一般来说需要关注的只有两个

css 选择器

quote.css('span.text::text').extract_first() 中的 'span.text::text'眼熟吗?
没错,就是我们常用的选择器。通过这个 api,我们可以把我们想要的数据,限时在一个很小的范围,然后拿字符串即可。
啥?你说你不会 css 选择器?前端培训-初级阶段(5 - 8)-CSS选择器(基本、层级、属性、伪类、伪状态)

  1. extract() 函数提取列表
  2. extract_first() 代表提取第一个元素。基本等价于 extract()[0]
  3. ::text 选择其中的文字
  4. ::attr(href) 提取属性

xpath

quote.xpath('span/small/text()').extract_first()
文档,这个我不会,我也没看

scrapy JSON

import json 使用这个类库解析如:json.loads(response.body.decode('utf-8'))

scrapy 请求方式

get

import urllib 可以用来给中文字符 encode

yield scrapy.FormRequest(
    url, 
    method = 'GET', 
    headers = self.headers, 
    formdata={}, 
    callback = self.parse_list, 
    dont_filter = True, 
    meta = {
        'offset': 0,
    })

post

数据放入 formdata 传递即可。

yield scrapy.FormRequest(
    url, 
    method = 'POST', 
    headers = self.headers, 
    formdata={}, 
    callback = self.parse_list, 
    dont_filter = True, 
    meta = {
        'offset': 0,
    })

给回调模块带参数

meta = {
        'offset': 0,
    }

如下方式接收

disstid = response.meta['offset']

外部传参方式

scrapy crawl argsSpider -a tag=爱情
内部是使用如下命令可以接收到。

    def start_requests(self):
        url = 'http://lab.scrapyd.cn/'
        tag = getattr(self, 'tag', None)  # 获取tag值,也就是爬取时传过来的参数

scrapy mysql

大数据那边说爬回来的数据要入库。

  1. scrapyMysql/scrapyMysql/items.py 编写对应入库字段。

    import scrapy
    
    class ScrapymysqlItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        tag = scrapy.Field()  # 标签字段
        cont = scrapy.Field()  # 名言内容
        pass
  2. scrapyMysql/scrapyMysql/spiders/inputMysql.py 写爬虫处理操作时,入库

    item = ScrapymysqlItem()  # 实例化item类
        for v in mingyan:  # 循环获取每一条名言里面的:名言内容、作者、标签
            item['cont'] = v.css('.text::text').extract_first()  # 提取名言
            tags = v.css('.tags .tag::text').extract()  # 提取标签
            item['tag'] = ','.join(tags)  # 数组转换为字符串
            yield item  # 把取到的数据提交给pipline处理
  3. 编写MySQL存储插件:MySQLPipeline.py

    import pymysql.cursors
    class MySQLPipeline(object):
        def __init__(self):
            # 连接数据库
            self.connect = pymysql.connect(
                host='127.0.0.1',  # 数据库地址
                port=3306,  # 数据库端口
                db='scrapyMysql',  # 数据库名
                user='root',  # 数据库用户名
                passwd='root',  # 数据库密码
                charset='utf8',  # 编码方式
                use_unicode=True)
            # 通过cursor执行增删查改
            self.cursor = self.connect.cursor()
    
        def process_item(self, item, spider):
            self.cursor.execute(
                """insert into mingyan(tag, cont)
                value (%s, %s)""",  # 纯属python操作mysql知识,不熟悉请恶补
                (item['tag'],  # item里面定义的字段和表字段对应
                 item['cont'],))
            # 提交sql语句
            self.connect.commit()
            return item  # 必须实现返回
  4. settings启动MySQLPipline组件

    ITEM_PIPELINES = {
       'scrapyMysql.MySQLPipline.MySQLPipeline': 300,
    }

总结一下

到现在,我们已经完成了所有基础知识的积累。遇到不会我们去里看?
总结一下需要注意点的

  1. 切换 PC 和 M 端,寻找可行的方案
  2. 注意节制(部分容易限量)
  3. python 编码问题(真的好烦)
  4. 网上提供的那个 mysql 库和我的不合,我换了一个MySQLdb
  5. 第三方的接口是真香

微信公众号

clipboard.png

阅读 5.1k

javascript-lNong
只此一生,何必从众

Read-Search-Ask

22.7k 声望
4.8k 粉丝
0 条评论

Read-Search-Ask

22.7k 声望
4.8k 粉丝
文章目录
宣传栏