为了账号安全,请及时绑定邮箱和手机立即绑定

用chrome插件实现cookie同步

2019.06.24 08:45 4087浏览

场景描述

做过爬虫或者机器人的朋友一定会遇到登陆的问题:大多数的网站需要登陆之后才能读取内容或者执行操作。要实现网站的自动化登陆和操作,大概的方法有两种:1,通过Chrome无头浏览器-selenium等工具模拟登陆,然后通过控制selenium实现和网站的交互操作;2,将包含已登陆信息的cookie设置到HTTP请求当中,直接通过HTTP request进行交互;这两种方法各自适用不同的场景,互相不能替代。但总的来说,当已经摸清服务器HTTP API的时,第二种方法是最直接有效,代码也是最简洁的。

面对的问题

对于第一种方法来说,最麻烦的是处理现在越来越繁复的验证码校验。虽然google和baidu 都有发布过一些包可以识别图片中的验证码,但准确率并不高;并且遇到需要手动拖拽的防机器人校验还得加入复杂的js代码进行动作模拟;

对于第二种方法,关键是如何获取cookie并妥善的处理cookie中登陆token过时的问题。我这篇文章提供一个简单的解决思路,虽然没有完全的自动化,但是只是部分解决了获取cookie和将cookie同步到机器人端的问题

解决思路

首先,我们需要在平时我们访问网站的时候,能够自动的将cookie保存下来,并且发送到云数据库中,方便机器人获取该cookie

其次,在每次机器人运行对应的工作时,都到云数据库中获取对应网站最新的cookie,再执行自动化操作。

这样做的好处在于:

  1. 我们不需要写复杂的代码去模拟登陆
  2. 每次我们访问常用网站的时候都会将最新的cookie更新到数据库,避免机器人使用的cookie过时

比如,我访问csdn,可以从下图看到,chrome已经自动导出了我的cookie,并且同步到了我的aws dynamoDB当中。
图片描述
要让chrome能实现这样的行为,我们需要自己开发chrome插件,所幸的是,代码量并不大。

使用插件主要基于以下原因:

  1. 对于大部分的用户登陆信息(user token等)来说,在保存到cookie中时,都带了HTTP_ONLY的flag,这个flag作为一个安全机制,目前基本已经成为一个业内标准。即当cookie中的值被标记为HTTP_ONLY时,在js脚本中无法通过document.cookie获取。即,如果你希望在js中获取当前页面的cookie时,document.cookie只能获取部分内容(非HTTP_ONLY)。而chrome plugin因为有更高的操作权限,可以通过chrome.cookies接口获取所有的cookie
  2. 因为我们期望的操作是获取用户登陆信息并同步到远端,数据安全尤为重要,以插件的方式进行操作,可以有效的隔离危险,防止被窥探

chrome cookie share插件开发

我这里只提一下重点,贴一下代码,关于具体的教程可以自行在网上搜索。这里给出google chrome的开发者官网。对接口有不清楚的可以到这上面去看一下。

项目结构

CookieShareHelper lex$ tree
.
├── images
│   ├── star_128px.ico
│   ├── star_132.png
│   ├── star_16.png
│   ├── star_16px.ico
│   ├── star_24.png
│   ├── star_24px.ico
│   ├── star_32px.ico
│   ├── star_33.png
│   ├── star_48px.ico
│   ├── star_49.png
│   ├── star_64px.ico
│   ├── star_66..png
│   ├── star_72px.ico
│   ├── star_74.png
│   ├── star_96px.ico
│   └── star_99.png
├── js
│   ├── aws-sdk.min.js
│   ├── background.js
│   └── content.js
└── manifest.json

主要的只有三个文件:

  • manifest.json
  • content.js
  • background.js

manifest.json

类似node开发里的package.json,里面定义了chrome插件的信息和结构。

{
  "manifest_version": 2,
  "name": "Cookie分享工具",
  "version": "1.0",
  "description": "将常用的网站的cookie保存到dynamoDB上,方便爬虫等工具直接使用",
  "icons": {
    "16": "images/star_16.png",
    "48": "images/star_49.png",
    "128": "images/star_132.png"
  },
  "browser_action": {
    "default_icon": {
      "19": "images/star_24.png",
      "38": "images/star_49.png"
    },
    "default_title": "Cookie分享工具"
  },
  "background": {
    "scripts": [
      "js/aws-sdk.min.js",
      "js/background.js"
    ]
  },
  "permissions": [
    "cookies",
    "tabs",
    "http://*/*",
    "https://*/*",
    "storage"
  ],
  "content_scripts": [
    {
      "matches": [
        "https://lex-lee.blog.csdn.net/"
      ],
      "js": [
        "js/content.js"
      ],
      "run_at": "document_end",
      "exclude_globs": [],
      "include_globs": [
        "*"
      ]
    }
  ]
}

还是对应到node的开发:

这里的background, 相当于后端

 "background": {
    "scripts": [
      "js/aws-sdk.min.js", //background需要使用aws-sdk.min.js中的变量,通过这行加载
      "js/background.js"
    ]
  }

content_scripts, 相当于前端。

  "content_scripts": [
    {
      "matches": [ //对应的页面才执行该脚本
        "https://lex-lee.blog.csdn.net/"
      ], 
      "js": [
        "js/content.js"
      ],
      "run_at": "document_end", //对应的页面加载完之后执行脚本
      "exclude_globs": [],
      "include_globs": [
        "*"
      ]
    }
  ]

这里需要注意的是,cookies不是默认的chrome组件,必须手动添加

  "permissions": [
    "cookies", //这行必不可少
    "tabs",
    "http://*/*",
    "https://*/*",
    "storage"
  ]

前端:content.js

这部分的代码超简单:主要是触发后端去进行cookie的更新,这里需要注意的是,content和background是运行在两个环境当中,它们需要通过onMessage通信机制进行通信

window.addEventListener("load", myMain, false);

function getCookies(url) {
  chrome.runtime.sendMessage({url: url}, async function (response) {
    console.log(response);
  });
}

function myMain(evt) {
  console.log("Cookie share helper running!");
  getCookies(document.URL)
}

后端:background.js

AWS.config.update({
  region: "YOUR region",
  accessKeyId: "aws密钥KeyId",
  secretAccessKey: "aws密钥key"
});

var docClient = new AWS.DynamoDB.DocumentClient();
var table = "DynamoDB的table名";
var id = "csdn";

function updateCookie(currentCookie) {


  var params = {
    TableName: table,
    Key: {
      "id": id
    }
  };

  docClient.get(params, function (err, data) {
    if (err) {
      console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
    } else {
      console.log("GetItem succeeded:");
      if (data != currentCookie) {
        console.log("GetItem succeeded:");
        putItem(currentCookie)
      }
    }
  });
}

function putItem(cookie) {
  var params = {
    TableName: table,//要操作的表名
    Item: {
      "id": id,//主键-分区间
      "cookie": cookie,
    }
  };
  docClient.put(params, function (err, data) {
    if (err) {
      console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
    } else {
      console.log("Added item:", JSON.stringify(data, null, 2));
    }
  });
}

chrome.runtime.onMessage.addListener(
  (request, sender, sendResponse) => {
    console.log(request);
    chrome.cookies.getAll({
      url: request.url
    }, (cks) => {
      let cookie = cks.map((item) => {
          return item.name + "=" + item.value
        }).join(";") + ";";
      updateCookie(cookie);
    });
    sendResponse("cookie update are trigger");
  });

结语

通过以上代码,我们实现了一个简单的登陆即同步cookie的功能,如果对你有帮助,烦请关注并点赞!谢谢

点击查看更多内容
0人点赞

若觉得本文不错,就分享一下吧!

评论

相关文章推荐

正在加载中
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消