模拟登录 pixiv.net

注意:本文的方法已作废,新方法在这里

由于 pixivAPI 有一些内容无法获取,于是模拟登录就派上用场辣

旧版登录接口 (https://www.secure.pixiv.net/login.php) 已经作废。目前新版登录页是用 React 渲染的,但是还是为老浏览器用户开启了兼容♂通道,首先找出这段表单代码:

<div id="old-login" style="display: none;">
  <form action="/login" method="POST">
    <input type="hidden" name="post_key" value="b827a089c8e7209503d23235d2ba4b43">
    <input type="hidden" name="return_to" value="http://www.pixiv.net/">
    <input type="hidden" name="lang" value="zh">
    <input type="hidden" name="source" value="pc">
    <div class="input-field-group">
      <div class="input-field">
        <input type="text" name="pixiv_id" placeholder="邮箱地址/pixiv ID" autocapitalize="off" autocomplete="off">
      </div>
      <div class="input-field">
        <input type="password" name="password" placeholder="密码" autocapitalize="off" autocomplete="off">
      </div>
    </div>
    <ul class="error-msg-list"></ul>
    <button type="submit" class="signup-form__submit">登录</button>
    <div class="signup-form-nav">
      <div class="left"></div>
      <div class="right"><a href="https://www.pixiv.net/reminder.php" target="_blank">忘记了</a></div>
    </div>
  </form>
</div>

发现需要 post 如下参数:

参数名说明
post_key类似于 token
return_to回跳地址
lang语言
source来源
pixiv_id用户名
password密码

提交的表单网址: https://accounts.pixiv.net/login

因为有 token 的存在,所以提交的时候也需要登录页的生成的 cookie,不提交 cookie 的后果就是如下的 400 Bad Request:(/´Д`)/

下面直接上全宇宙最好的语言进行登录(啪)
需要注意,首先需要安装一个 HTML DOM 解析包 sunra/php-simple-html-dom-parse ,运行一下 composer require "sunra/php-simple-html-dom-parser" 就行了。

主要的代码:

use Sunra\PhpSimple\HtmlDomParser;

define('BEFORE_LOGIN_COOKIE', __DIR__ . '/BEFORE_LOGIN_COOKIE.txt');//登录页面的cookie
define('AFTER_LOGIN_COOKIE', __DIR__ . '/AFTER_LOGIN_COOKIE.txt');//登录成功后获取到的cookie
define('USER_AGENT', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36');

function login_pixiv($username, $password)
{
    $login_url = 'https://accounts.pixiv.net/login';
    //获取登陆页cookie
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $login_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_COOKIEJAR, BEFORE_LOGIN_COOKIE);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
    curl_setopt($ch, CURLOPT_TIMEOUT, 15);
    curl_setopt($ch, CURLOPT_USERAGENT, USER_AGENT);

    $login_html = curl_exec($ch);

    curl_close($ch);

    $dom = HtmlDomParser::str_get_html($login_html);

    $form = $dom->find('#old-login', 0)->find('form', 0);

    $data['post_key'] = $form->find('input[name="post_key"]', 0)->value;
    $data['return_to'] = $form->find('input[name="return_to"]', 0)->value;
    $data['lang'] = $form->find('input[name="lang"]', 0)->value;
    $data['source'] = $form->find('input[name="source"]', 0)->value;
    $data['pixiv_id'] = $username;
    $data['password'] = $password;

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $login_url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_COOKIEFILE, BEFORE_LOGIN_COOKIE);
    curl_setopt($ch, CURLOPT_COOKIEJAR, AFTER_LOGIN_COOKIE);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
    curl_exec($ch);
    curl_close($ch);
}

调用 login_pixiv() 方法登录成功获取到 cookie 后,就可以为♂所♂欲♂为了,这个 cookie 的有效期为一个月,提供一个验证 cookie 是否有效的方法:

function is_cookie_ok($cookie)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'http://www.pixiv.net/setting_profile.php');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HEADER, 1);
    curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
    curl_setopt($ch, CURLOPT_TIMEOUT, 15);
    curl_setopt($ch, CURLOPT_USERAGENT, USER_AGENT);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
    $response = curl_exec($ch);
    curl_close($ch);
    $headers = [];

    $header_text = substr($response, 0, strpos($response, "\r\n\r\n"));

    foreach (explode("\r\n", $header_text) as $i => $line) {
        if ($i === 0) {
            $headers['http_code'] = $line;
        } else {
            list($key, $value) = explode(': ', $line);

            $headers[$key] = $value;
        }
    }

    if (strpos($headers['http_code'], '200') === false) {
        return false;
    }
    return true;

}