// .Net4
// HttpWebRequestなデータ取得方法
// こっちはうまく動いてる
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
namespace PixivGetter
{
public class PixivAPI : IDisposable
{
const string API_URI = "http://spapi.pixiv.net/iphone/";
const double items_per_page = 1.0 / 50;
private string SSID = null;
public PixivAPI(string userID, string userPass, int timeout = 10000)
{
Debug = false;
RetakeSSID(userID, userPass);
}
public string RetakeSSID(string userID, string userPass)
{
try
{
if (userID == "") throw new Exception("userIDが空です");
if (userPass == "") throw new Exception("userPassが空です");
string post_mes = "mode=login&pixiv_id=" + userID + "&pass=" + userPass + "&skip=0";
Match m = Regex.Match(getQueryByPost(API_URI + "login.php", post_mes), "PHPSESSID=([0-9a-f]+)");
if (!m.Success) throw new Exception("SSIDが取得できません");
SSID = m.Groups[1].Value;
}
catch (Exception ex)
{
throw new Exception("pixiv login error\r\n" + ex.ToString());
}
return SSID;
}
public void Dispose()
{
if (dbg != null) dbg.Dispose();
}
// POSTしてレスポンスのQuery文字列を得る
private string getQueryByPost(string url, string post_mes)
{
byte[] postData = System.Text.Encoding.ASCII.GetBytes(post_mes);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = postData.Length;
req.ProtocolVersion = HttpVersion.Version11;
using (System.IO.Stream st = req.GetRequestStream())
{
st.Write(postData, 0, postData.Length);
}
return req.GetResponse().ResponseUri.Query;
}
// pixiv apiで文字列取得
private string getData(string api, string query)
{
var res = HttpWebRequest.Create(API_URI + api + ".php?dummy=0&" + query + "&PHPSESSID=" + SSID).GetResponse();
using (Stream st = res.GetResponseStream())
using (StreamReader sr = new StreamReader(st, Encoding.UTF8))
{
return sr.ReadToEnd();
}
}
// 個数から必要ページ数を計算
public uint PagesOf(int items)
{
return (uint)Math.Ceiling(items * items_per_page);
}
// pixiv apiでデータ取得
private List<PixivInfo> getPixivInfoList(string method, string query)
{
return PixivInfo.ParseCSV(dbgWrite(getData(method, query)));
}
// "お気に入りユーザーの新着"の pageNo ページを取得
public List<PixivInfo> BookmarkUserNewIllust(uint pageNo = 1)
{
return getPixivInfoList("bookmark_user_new_illust", "p=" + pageNo.ToString());
}
// "お気に入りユーザーの新着"の pageFrom~pageTo ページを取得
public List<PixivInfo> BookmarkUserNewIllustFromTo(uint pageFrom, uint pageTo)
{
List<PixivInfo> ps = new List<PixivInfo>();
for (uint i = pageFrom; i <= pageTo; i++)
ps.AddRange(BookmarkUserNewIllust(i));
return ps;
}
// メンバーのイラスト件数を取得
public uint MemberIllustCount(uint memberID)
{
return uint.Parse(getData("member_illust", "id=" + memberID.ToString() + "&c_mode=count"));
}
// メンバーのイラスト情報のpageNoページを取得
public List<PixivInfo> MemberIllust(uint memberID, uint pageNo = 1)
{
return getPixivInfoList("member_illust", "id=" + memberID.ToString() + "&p=" + pageNo.ToString());
}
// メンバーのイラスト情報のpageFrom~pageToページを取得
public List<PixivInfo> MemberIllustFromTo(uint memberID, uint pageFrom, uint pageTo)
{
List<PixivInfo> ps = new List<PixivInfo>();
for (uint i = pageFrom; i <= pageTo; i++)
ps.AddRange(MemberIllust(memberID, i));
return ps;
}
// メンバーのイラスト情報を全部取得
public List<PixivInfo> MemberIllustAll(uint memberID)
{
return MemberIllustFromTo(memberID, 1, (uint)PagesOf((int)MemberIllustCount(memberID)));
}
// イラストIDのイラスト情報を取得
public List<PixivInfo> Illust(uint illustID)
{
return getPixivInfoList("illust", "illust_id=" + illustID.ToString() + "&p=1");
}
//----------------------------------------------
// デバッグ用
private Debugger dbg = null;
public bool Debug
{
get
{
return dbg != null;
}
set
{
if (value && dbg == null) dbg = new Debugger();
if (!value && dbg != null) { dbg.Dispose(); dbg = null; }
}
}
private string dbgWrite(string str)
{
if (dbg != null) dbg.Write(str);
return str;
}
private string dbgWriteLine(string str)
{
if (dbg != null) dbg.WriteLine(str);
return str;
}
}
// apiが返すデータの格納用
public class PixivInfo
{
public uint IllustID { get; protected set; }
public uint MemberID { get; protected set; }
public string Ext { get; protected set; }
public string Title { get; protected set; }
public int ImgSrv { get; protected set; }
public string Author { get; protected set; }
public string ThumURL { get; protected set; }
public string MobileImgURL { get; protected set; }
public string Date { get; protected set; }
public string[] Tags { get; protected set; }
public string[] Tools { get; protected set; }
public uint AppCount { get; protected set; }
public uint TotalPoint { get; protected set; }
public uint Views { get; protected set; }
public string Comment { get; protected set; }
public uint Manga { get; protected set; }
public uint BMCount { get; protected set; }
public string User { get; protected set; }
enum State { Default, Quoted };
internal PixivInfo(List<string> pi)
{
IllustID = pi[0] == "" ? 0 : uint.Parse(pi[0]);
MemberID = pi[1] == "" ? 0 : uint.Parse(pi[1]);
Ext = pi[2];
Title = pi[3];
ImgSrv = pi[4] == "" ? 0 : int.Parse(pi[4]);
Author = pi[5];
ThumURL = pi[6];
// 7~8
MobileImgURL = pi[9];
// 10~11
Date = pi[12];
Tags = Regex.Split(pi[13], " ");
Tools = Regex.Split(pi[14], " ");
AppCount = pi[15] == "" ? 0 : uint.Parse(pi[15]);
TotalPoint = pi[16] == "" ? 0 : uint.Parse(pi[16]);
Views = pi[17] == "" ? 0 : uint.Parse(pi[17]);
Comment = pi[18];
Manga = pi[19] == "" ? 0 : uint.Parse(pi[19]);
BMCount = pi[22] == "" ? 0 : uint.Parse(pi[22]);
User = pi[24];
}
// 画像のURLリスト
public List<string> ImgURLs
{
get
{
List<string> rs = new List<string>();
string fmt = "http://img{0:D2}.pixiv.net/img/{1}/{2:D}";
if (Manga > 0)
{
if (IllustID > 11231118) // 1000万(?)を境にオリジナルサイズの _big が追加された模様
// 少なくとも11231118には_bigがないことを確認済み
fmt += "_big_p{4:D}.{3}";
else
fmt += "_p{4:D}.{3}";
for (int i = 0; i < Manga; i++)
rs.Add(String.Format(fmt, ImgSrv, User, IllustID, Ext, i));
}
else
{
fmt += ".{3}";
rs.Add(String.Format(fmt, ImgSrv, User, IllustID, Ext));
}
return rs;
}
}
// apiが返すCSVもどきのデータをパースする
internal static List<PixivInfo> ParseCSV(string str)
{
List<PixivInfo> ps = new List<PixivInfo>();
List<string> pi = new List<string>();
string item = "";
State st = State.Default;
foreach (var c in str)
{
switch (st)
{
case State.Default:
switch (c)
{
case '"':
st = State.Quoted;
item += c;
break;
case ',':
pi.Add(strip_quote(item));
item = "";
break;
case '\n':
pi.Add(strip_quote(item));
ps.Add(new PixivInfo(pi));
pi = new List<string>();
item = "";
break;
default:
item += c;
break;
}
break;
case State.Quoted:
if (c == '"') st = State.Default;
item += c;
break;
default:
throw new Exception("パースエラー");
}
}
if (pi.Count > 0) ps.Add(new PixivInfo(pi));
return ps;
}
// 文字列の最初と最後の"を削除
internal static string strip_quote(string str)
{
if (str.Length == 0) return str;
int b = str.StartsWith("\"") ? 1 : 0;
int e = str.Length - (str.EndsWith("\"") ? 2 : 1);
return str.Substring(b, e);
}
}
}