
はてなキーワード:parseとは
タスクタイプのENUMとタスク内容のStringと日付をDBに保存するコマンドプログラムを書いて タスク内容はタスクタイプによっては固定になる場合と任意のStringの場合がある
これで下のようなものが出たがENUM側に持たせてるので言い方の問題だと思うよ
public staticvoidmain(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Task type:");
for (TaskType type : TaskType.values()) {
System.out.println("- " + type.name());
}
TaskType taskType = TaskType.valueOf(scanner.nextLine().trim());
if (taskType.hasFixedContent()) {
taskContent = taskType.getFixedContent();
System.out.println("Task content fixedas: " + taskContent);
} else {
System.out.print("Enter task content: ");
taskContent = scanner.nextLine();
}
System.out.print("Enter taskdate (yyyy-MM-dd): ");
LocalDate taskDate = LocalDate.parse(scanner.nextLine());
Task task = new Task(taskType, taskContent, taskDate);
System.out.println("Task saved successfully.");
}
}
DAILY_REPORT("Daily report submission"),
MEETING(null),
MAINTENANCE("Systemmaintenance task");
privatefinalString fixedContent;
TaskType(String fixedContent) {
this.fixedContent = fixedContent;
}
public boolean hasFixedContent() {
return fixedContent != null;
}
publicString getFixedContent() {
return fixedContent;
}
}
パーサ【parser】パーザ
パーサとは、コンピュータプログラムのソースコードやXML文書など、何らかの言語で記述された構造的な文字データを解析し、プログラムで扱えるようなデータ構造の集合体に変換するプログラムのこと。 そのような処理のことを「構文解析」「パース」(parse)という。2025/08/29
https://e-words.jp › パーサ
「Purser」とはどういう意味ですか?
なお、かつては女性の「客室乗務員」のことを「スチュワーデス」、男性の「客室乗務員」のことを「スチュワード」や「パーサー」と呼んでいたが、今では旅客機に限らず鉄道や客船の中で、乗客に接客サービスをする「客室乗務員」を統率する立場にある者を「パーサー」や「チーフパーサー」と呼んでいる。
一度投稿したうえで別タブを開いてプログラム的(fetch)に送信してその別タブが閉じられる仕組み。
// ==UserScript== // @namePGP未署名検出と別タブ自動編集 // @namespacehttp://tampermonkey.net/ // @version 1.0 // @descriptionPGP署名がない投稿を自動編集ページへ誘導 // @matchhttps://anond.hatelabo.jp/* // @grantGM_setValue // @grantGM_getValue // @grantGM.openInTab // ==/UserScript== (function () { 'use strict';constbody = document.getElementById('entry-page'); if (!body) return;consttitleText = document.title; if (!titleText.includes('dorawii')) return;constpgpRegex = /BEGIN.*PGP(?: SIGNEDMESSAGE| SIGNATURE)?/;const preElements = document.querySelectorAll('div.body pre'); let hasPgpSignature =false; for (const pre of preElements) { if (pgpRegex.test(pre.textContent)) { hasPgpSignature =true; break; } } if (hasPgpSignature) return;const editLink = document.querySelector('a.edit');const childTab =GM.openInTab(editLink.href, {active:false, insert:true,setParent:true }); })();
// ==UserScript== // @name編集ページ処理と自動送信・閉じ // @namespacehttp://tampermonkey.net/ // @version 1.0 // @description編集ページで署名処理と送信、タブ自動閉じ // @matchhttps://anond.hatelabo.jp/dorawii_31/edit?id=* // @grantGM_getValue // @grantGM_xmlhttpRequest // @grantGM_setClipboard // @grantGM_notification // @connectlocalhost // ==/UserScript== (async function () { 'use strict';const shouldRun = awaitGM_getValue('open-tab-for-edit', '0');consttextareaId = 'text-body';consttextarea = document.getElementById(textareaId); if (!textarea) return;const content =textarea.value;constpgpSignatureRegex = /-----BEGINPGP SIGNEDMESSAGE-----[\s\S]+?-----BEGINPGP SIGNATURE-----[\s\S]+?-----ENDPGP SIGNATURE-----/; if (pgpSignatureRegex.test(content)) {console.log('[PGPスクリプト]署名が検出されたためそのまま送信します'); return; }consthttpRequest = (url, data) => { return newPromise((resolve,reject) => {GM_xmlhttpRequest({ method: 'POST',url:url, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, data: `value=${encodeURIComponent(data)}`,onload: function (response) { resolve(response.responseText); },onerror: function (error) {reject(error); } }); }); }; //textarea の値を取得 // 1.現在のページのURLからURLオブジェクトを作成const currentUrl = newURL(window.location.href); // 2.ベースとなる部分 (例: "https://anond.hatelabo.jp") を取得constorigin = currentUrl.origin; // 3. 'id'パラメータの値 (例: "20250610184705") を取得constidValue = currentUrl.searchParams.get('id'); // 4.ベース部分とIDを結合して、目的のURL文字列を生成 //idValueが取得できた場合のみ実行する let newUrl = null; if (idValue) { newUrl = `${origin}/${idValue}`; } // 5. 生成されたURLを変数に代入し、コンソールに出力して確認console.log(newUrl);constvalueToSend = newUrl;try {const signatureText = awaithttpRequest('http://localhost:12345/run-batch',valueToSend);console.log('バッチ応答:', signatureText); if (!signatureText.includes('BEGINPGP SIGNEDMESSAGE')) { alert('PGP署名がクリップボードに見つかりませんでした。'); return; }const newText = content.replace(/\s*$/, '') + '\n' + signatureText + '\n';textarea.value = newText;console.log('[PGPスクリプト]署名を貼り付けました。送信を再開します。');const form = document.forms.edit;const newForm = form.cloneNode(true); form.replaceWith(newForm); newForm.addEventListener('submit', async (e) => { e.preventDefault(); //HTML標準のsubmitをキャンセルconstbodyText =textarea?.value || ''; //reCAPTCHAトークンの取得constrecaptchaToken = await newPromise((resolve) => { grecaptcha.enterprise.ready(() => { grecaptcha.enterprise.execute('hoge', {action: 'EDIT' }) .then(resolve); }); }); // POSTするデータの構築const formData = new FormData(newForm); formData.set('body',bodyText); formData.set('recaptcha_token',recaptchaToken); formData.set('edit', '1');try {constresponse = await fetch(newForm.action, { method: 'POST',body: formData, credentials: 'same-origin' }); if (response.ok) {console.log('送信成功'); window.close(); } else {console.error('送信失敗',response.status); } }catch (err) {console.error('送信中にエラーが発生', err); } }); //プログラム的に送信トリガー newForm.dispatchEvent(new Event('submit', { bubbles:true })); }catch (e) {console.error('バッチ呼び出し失敗:', e); } })();
consthttp =require('http');const { exec } =require('child_process');const querystring =require('querystring');const server =http.createServer((req, res) => { if (req.method === 'GET' && req.url === '/ping') { res.writeHead(200); res.end('pong'); } else if (req.method === 'POST' && req.url === '/run-batch') { letbody = ''; req.on('data', chunk => {body += chunk.toString(); }); req.on('end', () => {constparsed = querystring.parse(body);constvalue =parsed.value || 'default'; // 値を引数としてバッチに渡す exec(`C:\\Users\\hoge\\Desktop\\makesign.bat "${value}"`, { encoding: 'utf8' }, (err, stdout, stderr) => { if (err) { res.writeHead(500); res.end('Error executing batch: ' + stderr); } else { res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' }); res.end(stdout.trim()); } }); }); } else { res.writeHead(404); res.end('Not found'); }});server.listen(12345, () => {console.log('Batch serverrunningathttp://localhost:12345/');});
@echo offsetlocal enabledelayedexpansion::署名するファイル名set "infile=%~1"set outfile=%TEMP%\pgp_output.asc:: 以前の出力があれば削除if exist "%outfile%" del "%outfile%":signloop::AutoHotkeyでパスフレーズ入力(gpgがパスワード要求するダイアログが出た場合に備える)start "" /b "C:\Users\hoge\Documents\AutoHotkey\autopass.ahk"::PGPクリア署名を作成echo %infile% | gpg --yes --clearsign --output "%outfile%"::署名が成功していればループを抜けるif exist "%outfile%" (goto postprocess) else ( timeout /t 1> nulgoto signloop):postprocesspowershell -nologo -command ^ "$header = '>|'; $footer = '|<'; $body =Get-Content '%outfile%' -Raw;Write-Output ($header + \"`r`n\" + $body + $footer)"powershell -nologo -command ^ "$header = '>|'; $footer = '|<'; $body =Get-Content 'signed.asc' -Raw;Set-Clipboard -Value ($header + \"`r`n\" + $body + $footer)"endlocalexit /b
#Persistent#SingleInstance ignoreSetTitleMatchMode, 2WinWaitActive, pinentrySendInputpasswordSleep 100SendInput {Enter}ExitApp
動けばいいという考えで作っているので余分なコードも含んでいるかもしれない。
-----BEGINPGP SIGNEDMESSAGE-----Hash: SHA512https://anond.hatelabo.jp/20250613185036 -----BEGINPGP SIGNATURE-----iHUEARYKAB0WIQTEe8eLwpVRSViDKR5wMdsubs4+SAUCaEv1FQAKCRBwMdsubs4+SHHkAQDUOLgBcdji2T6MJ7h/vlMdFfGlWAzNdXijjE1gIuEPywEAiMNMZqhrMmtlc7UqRuggNJ/UTa5xTIcKp622+7jJQQg==Lgkl-----ENDPGP SIGNATURE-----
ようやく(ほぼ)すべてが自動化された。
あとはローカルサーバーの起動をスタートアップに設定する(方法をAIに聞いて指示に従う)だけの消化試合。
署名時要求してくるパスワードを自動入力するahkファイルはドキュメントのAutoHotkey配下に置いた。
バッチファイル(make.sign.bat)はデスクトップに置いた。
#Persistent#SingleInstance ignoreSetTitleMatchMode, 2WinWaitActive, pinentrySendInput お前のパスワードSleep 100SendInput {Enter}ExitApp
//run-batch-server.jsconsthttp =require('http');const { exec } =require('child_process');const server =http.createServer((req, res) => { if (req.url === '/ping') { res.writeHead(200); res.end('pong'); } else if (req.url === '/run-batch') { exec('C:\\Users\\you\\Desktop\\makesign.bat', (err) => { res.writeHead(200); res.end(err ? 'Error' : 'OK'); }) ; } else { res.writeHead(404); res.end('Not found'); }});server.listen(12345, () => {console.log('Batch serverrunningathttp://localhost:12345/');});
@echo offsetlocal enabledelayedexpansion::ミリ秒単位のUTC時刻を取得for /f %%a in ('powershell -nologo -command "[int64]::Parse((Get-Date).ToUniversalTime().ToString('yyyyMMddHHmmssfff'))"') doset timestamp=%%a::署名するファイル名set infile=%TEMP%\pgp_input.txtset outfile=%TEMP%\pgp_output.asc:: 以前の出力があれば削除if exist "%outfile%" del "%outfile%"::タイムスタンプを原文として保存echo %timestamp%> "%infile%":signloop::AutoHotkeyでパスフレーズ入力(gpgがパスワード要求するダイアログが出た場合に備える)start "" /b "C:\Users\infini\Documents\AutoHotkey\autopass.ahk"::PGPクリア署名を作成gpg --yes --clearsign --output "%outfile%" "%infile%"::署名が成功していればループを抜けるif exist "%outfile%" (echo [INFO]署名成功goto postprocess) else (echo [WARN]署名失敗、再試行します… timeout /t 1> nulgotosignloop):postprocess::PowerShellで余計な改行なしに |< をつけてクリップボードにコピーpowershell -nologo -command ^ "$header = '>|'; $footer = '|<'; $body =Get-Content '%outfile%' -Raw;Set-Clipboard -Value ($header + \"`r`n\" + $body + $footer)"echo Done.signed.asc created and clipboard updated (no extra blankline).endlocalexit /b
// ==UserScript==// @namePGP署名自動付加スクリプト(GM_xmlhttpRequest版)// @namespacehttp://tampermonkey.net/// @version 1.0// @description投稿前にPGP署名を付けてから送信(fetch未使用)// @matchhttps://anond.hatelabo.jp/dorawii_31/edit*// @grant GM_xmlhttpRequest// @grant GM_setClipboard// @grant GM_notification// / @connectlocalhost// ==/UserScript==(function () { 'use strict';const submitId = 'submit-button';consttextareaId = 'text-body';const localServer = 'http://localhost:12345/run-batch';constpgpSignatureRegex = /-----BEGINPGPSIGNEDMESSAGE-----[\s\S]+?-----BEGINPGPSIGNATURE-----[\s\S]+?-----ENDPGPSIGNATURE-----/;consthttpRequest = (url) => { return newPromise((resolve,reject) => { GM_xmlhttpRequest({ method: 'GET',url:url, onload: function (response) { resolve(response.responseText); }, onerror: function (error) {reject(error); } }); }); };const interceptClick = () => {constbtn = document.getElementById(submitId); if (!btn ||btn.dataset.pgpIntercepted === 'true') return;btn.dataset.pgpIntercepted = 'true';btn.addEventListener('click', async function (e) {consttextarea = document.getElementById(textareaId); if (!textarea) return;const content =textarea.value; if (pgpSignatureRegex.test(content)) {console.log('[PGPスクリプト]署名が検出されたためそのまま送信します'); return; } e.preventDefault(); e.stopImmediatePropagation();console.log('[PGPスクリプト]署名が見つからないため処理を停止し、署名を取得します');try { awaithttpRequest(localServer); //バッチ実行constsignatureText = await navigator.clipboard.readText(); if (!signatureText.includes('BEGINPGPSIGNEDMESSAGE')) { alert('PGP署名がクリップボードに見つかりませんでした。'); return; }const newText = content.replace(/\s*$/, '') + '\n' +signatureText + '\n';textarea.value = newText;console.log('[PGPスクリプト]署名を貼り付けました。送信を再開します。');btn.click(); //イベント再発火 }catch (err) { alert('PGP署名の取得または貼り付けに失敗しました。\n' + err); } },true); }; window.addEventListener('load', () => {setTimeout(interceptClick, 1000); });})();
プロミスメソッドとか全然まだ理解してなくてそのなかに関数代入したその関数にオブジェクトのプロパティにresponseを?いやまあそのあたりのコードが示すデータの流れが全然理解できないような人間でもここまでできちゃった。
AIすごいなと思うよ。そして思うのは今後重要になってくるのは文法とか自体に詳しいことじゃなくて、そのプログラムの処理内容を指示できるシステムエンジニア的な言語化能力のほうじゃないかなと思った。
-----BEGINPGPSIGNEDMESSAGE-----Hash: SHA51220250609111559680 -----BEGINPGPSIGNATURE-----iHUEARYKAB0WIQTEe8eLwpVRSViDKR5wMdsubs4+SAUCaEbCbwAKCRBwMdsubs4+SLueAPwOv7PBk4voAe5qlcCEvs/PJhmKc5QAb/1R43JMQFuDZgD/UTPEKsL/PhK9jFGv2HDXK1dVjLNwvosgX9uYJh5xxwY==qiOE-----ENDPGPSIGNATURE-----
ChatGPTにバッチファイルを作ってもらったのでこれからは署名が捗るぞ。これだけ手軽化できたらレスバに入っても署名つけるのも億劫にならずできそうだ。
なにせ文章を書き折ったらあとはバッチダブルクリックしてCtr+Vするだけだ。
名乗る人が増えることを期待して作らせたものを公開しておく。
@echo offsetlocal::ミリ秒単位のUTC時刻を取得for /f %%A in ('powershell -nologo -command "[int64]::Parse((Get-Date).ToUniversalTime().ToString('yyyyMMddHHmmssfff'))"') doset timestamp=%%A::PGPクリア署名を作成echo %timestamp% | gpg --yes --clearsign> signed.asc::PowerShellで余計な改行なしに |< をつけてクリップボードにコピーpowershell -nologo -command ^ "$header = '>|'; $footer = '|<'; $body =Get-Content 'signed.asc' -Raw;Set-Clipboard -Value ($header + \"`r`n\" + $body + $footer)"echo Done. signed.asc created and clipboard updated (no extra blankline).
-----BEGINPGP SIGNEDMESSAGE-----Hash: SHA51220250608045542542 -----BEGINPGP SIGNATURE-----iHUEARYKAB0WIQTEe8eLwpVRSViDKR5wMdsubs4+SAUCaEUXzgAKCRBwMdsubs4+SCvuAQDjRjPVCO1F9DgmAKoqKYG7qB9r4e7y2Ky+/umT/OhnygEA8h2NL8zIczSphcOk/MaDWJJ2Y7WDA3d6gxFakW8TKAw==HE4/-----ENDPGP SIGNATURE-----
令和7年4月1日以降、官報の帰化情報が90日経過で閲覧不可になった。
「プライバシーに配慮」とのことだが、最近の不自然な戸籍不要発言などと合わせて考えると嫌な予感しかしない。
そこでとりあえず官報を保存できるプログラムを作った。自分でダウンロードして保存すること自体は全く問題ない行為。
官報は平日の8:30に公開されるので、cronで8:31とかに実行すると良いのでは。
#官報のPDFデータを入手して保存するimport requestsimportosimporttimefrom bs4 import BeautifulSoupfromurllib.parse importurljoin#対象URLindex_url = "https://www.kanpo.go.jp/index.html"base_url = 'https://www.kanpo.go.jp/'#ダウンロード先フォルダdownload_dir = 'pdfs'os.makedirs(download_dir, exist_ok=True)# ページ取得response = requests.get(index_url)response.encoding = 'utf-8'text =response.text#HTMLを解析soup = BeautifulSoup(text, "html.parser")results = []# 「本日の官報」を対象にPDFの情報を取得するtoday_box = soup.find('div', class_='todayBox')if today_box:dl = today_box.find('dl')dt =dl.find('dt') ifdt: # 日付の抽出date_text =dt.get_text(strip=True).split('92;n')[0].replace(" ","").replace("全体目次はこちら","").replace("※インターネット版官報","").strip()dd =dl.find('dd') ifdd: for li indd.find_all('li', class_='articleBox'):title_tag = li.find('a', class_='articleTop')pdf_link = li.find('a', class_='pdfDlb') iftitle_tag andpdf_link:title =title_tag.decode_contents().replace("<br/>", "").strip()url =pdf_link['href'] results.append({ '日付':date_text, 'title':title, 'url':url })# 結果の表示for r in results:date = r['日付']title = r['title']url = r['url'] #pdfファイルのURLを作成url_parts =url.rsplit("/", 1)url_base =url_parts[0] filename =url_parts[1].replace("f.html", ".pdf") converted_url = f"{url_base}/pdf/{filename}" #pdfのURLとファイル名を作成 full_url =urljoin(base_url, converted_url) base_filename =date + "_" +title + "_" + filename.replace("f.html", ".pdf") #ダウンロードして保存print(f'Downloading {full_url} ...')try:response = requests.get(full_url)response.raise_for_status() withopen(os.path.join(download_dir, base_filename), 'wb')as f: f.write(response.content)print(f'Saved: {base_filename}')time.sleep(10) except Exceptionas e:print(f'Failed todownload {full_url}: {e}')
はてなブックマークのAPIを利用して 非公開 でブックマークする方法をご説明します。
2.OAuthのトークンを発行する。(個人用のスクリプトなら「パーソナルアクセストークン」推奨)
ブックマークを 非公開 にするには、APIのリクエストボディに privateフィールドを 1 に設定します。
エンドポイント:
POSThttps://bookmark.hatenaapis.com/rest/1/my/bookmark
リクエストボディ(JSON): { "url": "https://anond.hatelabo.jp/xxxxxxx", "comment": "自動ブックマーク", "private": 1}
以下のコードを実行すれば、10分以内の匿名ダイアリー記事をランダムに 非公開 でブックマークできます。
import feedparserimport requestsimport randomimporttimefrom datetime import datetime,timezone,timedelta#はてなAPIの認証情報HATENA_API_KEY = "あなたのAPIキー"HATENA_USERNAME = "あなたのはてなID"#はてな匿名ダイアリーのRSSURLRSS_URL = "https://anond.hatelabo.jp/rss"#10分以内の投稿を取得def get_recent_entries(): feed = feedparser.parse(RSS_URL) recent_entries = []now = datetime.now(timezone.utc) for entry in feed.entries: published_time = datetime(*entry.published_parsed[:6], tzinfo=timezone.utc) if (now - published_time) <timedelta(minutes=10): recent_entries.append(entry.link) return recent_entries#はてなブックマークに非公開で追加def bookmark_entry(entry_url):url = "https://bookmark.hatenaapis.com/rest/1/my/bookmark" headers = { "Authorization": f"Bearer {HATENA_API_KEY}", "Content-Type": "application/json" } payload = { "url": entry_url, "comment": "自動ブックマーク", "private": 1 # 非公開設定 }response = requests.post(url,json=payload, headers=headers) returnresponse.status_code# メイン処理whileTrue: entries = get_recent_entries() if entries: entry = random.choice(entries) status = bookmark_entry(entry)print(f"非公開ブックマーク: {entry},ステータス: {status}")time.sleep(600) #10分ごとに実行
• 実行環境:Python 3.x が必要。requests と feedparser をインストール (pip install requests feedparser)
• 実行間隔:time.sleep(600) で10分ごとに実行
•API制限:はてなAPIにはリクエスト制限があるため、短時間で大量に実行しないように注意
•OAuth認証:APIキーだけでなく、OAuthトークンを使うほうがより安全
このスクリプトを実行すれば、最新の匿名ダイアリー投稿を10分以内のものからランダムに選び、非公開でブックマークする ことができます。
OSのコマンドプロンプトはどうしてスペースを区切り文字としたのだろうか?もしタブを区切り文字として採用していれば、混乱はもっと少なかったと思うのだけど。
と、いう素朴な疑問からスタートし、タブが唯一の由緒正しい区切り文字として採用されていた世界線を考察しました。
https://grok.com/share/bGVnYWN5_aa43b346-0185-4f3e-ac4f-7712a59545c8
この世界線で、TABのみが由緒正しく使える使える区切り文字です。
tsvデータが主流となりcsvデータのparseで悩む人にいなくなる。
スペースとタブを区別するために[TAB]のようなフォントも作られるだろう。
さらに、プログラムのインデントもスペースではなく、すべてタブで行われるようになり、タブ幅は2なのか4なのか8なのか論争も起きなかっただろう。個人のエディタの設定で変えればいいだけですしね。
もちろん、ASCII規格のUS(Unit Separator,ASCII31):ユニット(フィールド)の区切り、に相当するキーがキーボードに搭載されていたとしたら、それを使うのが最良だったと思う。
しかしながら、多くのキーボードにはスペースキーかタブキーぐらいしかなく、これを使うことはできなかったでしょうね。
まとめ
コマンドの区切り文字にスペースを使ってしまった、インデントにスペースを使ってしまった。
この辺りの失敗が多くの人を悩ませていると思う。
import requestsimportjsonfromurllib.parse import quotedef fetch_bookmarks(url):try: #URLをエスケープ escaped_url = quote(url, safe="") api_url = f"https://b.hatena.ne.jp/entry/json/?url={escaped_url}"response = requests.get(api_url)response.raise_for_status()try: returnresponse.json() exceptjson.decoder.JSONDecodeErroras e:print(f"Error decodingJSON from {api_url}: {e}")print("Response content:",response.text) return [] except requests.exceptions.RequestExceptionas e:print(f"Error fetching bookmarks from {api_url}: {e}") return []def find_common_bookmarks(bookmarks1, bookmarks2,url1,url2): common_users =set(bm["user"] for bm in bookmarks1 if bm["comment"]) &set(bm["user"] for bm in bookmarks2 if bm["comment"]) common_bookmarks = [] foruser in common_users: comments = [] for bm in bookmarks1: if bm["user"] ==user and bm["comment"]: comments.append({"url":url1, "comment": bm["comment"], "timestamp": bm["timestamp"]})break for bm in bookmarks2: if bm["user"] ==user and bm["comment"]: comments.append({"url":url2, "comment": bm["comment"], "timestamp": bm["timestamp"]})break iflen(comments) == 2: common_bookmarks.append({"user":user, "comments": comments}) return common_bookmarksif __name__ == "__main__":url1 = "https://news.yahoo.co.jp/articles/f9966c4ccc374fc88babbb50175a9ea844c99638"url2 = "https://www.asahi.com/articles/ASN6K7F64N6KUJHB00L.html" data1 = fetch_bookmarks(url1) data2 = fetch_bookmarks(url2) common_bookmarks = find_common_bookmarks(data1["bookmarks"], data2["bookmarks"],url1,url2)print(json.dumps(common_bookmarks, indent=2, ensure_ascii=False))
url1,url2のところを対象としたいものに変えれば使えるよ
バグあったら直して使ってね
※架空言語、という事にしておいてほしいんだが
List<Record> rows =DBから持ってくる(); // 合計金額を求めるStringtotal = "0"; for (Record r : rows) {BigDecimal temp =BigDecimal.parse(カンマを削除する関数(total) );BigDecimal temp2 = temp + r.金額;total =カンマ区切りの文字列にする関数(temp2); } // やったー合計金額を計算してカンマ区切りの文字列にできたよー returntotal;
とか
// async await は非同期処理を同期してくれる魔法の言葉だって!よく知らんけど await axios.get('/foo') .then(function(result) { // やったー結果が得られたよー });
とか
正直なところ、こういうコードのお守りするの、そろそろキツい。。。
この時期になるとずっと気象庁の気温ランキングを眺めて「今日も暑いなー」って見てるんだが
https://www.data.jma.go.jp/obd/stats/data/mdrr/rank_daily/data00.html
このページの「観測値」が昔からずっとバグっててめっちゃ気になってる
「35.9 ]」っていう感じで、「]」が入ってる
もうバグの原因はほぼほぼ目に見えてて、ここはJSONで「 [ 34.0, 34.5, 35.0, 35.9 ]」っていう値が入ってて
それをJSON.parseするんじゃなくてsplit()とか使ってしかもlength-1とかで最新値を取ってる
なので後ろの括弧がそのまま入ってしまってる
こんなのめちゃくちゃわかりやすいバグだし、多分気象庁側も把握してるんだろうけど
多分発注しないとダメとかテストが必要だとかでずっと放置されてる
めっちゃ気になるのにずーーーーーっとこのままなのが凄くダサい
不正解でscore += 0; と書いているのは静的解析がelse節を省略すると指摘してくるから。
何もしていない、はそのとおり。
不等号がいい具合に化けてるのでそのままにしておく。
importjava.util.*;public classMain { public staticvoidmain(String[] args) { //入力のparse (中略:int numに問題の数、String list[i][] に問題のリストを格納している) // 採点 intpoint = 0; for (int i = 0; i < num; i++) {String question = list[i][0];Stringanswer = list[i][1]; if (question.equals(answer)) { // 完全一致point += 2; } else { if (question.length() ==answer.length()) { //文字数は等しい(部分点の可能性がある)point += scoring(question,answer); } else { //不正解point += 0; } } } System.out.println(point); } // 長さが同じ文字列を採点する // 長さが違う文字列を受け渡したときは正しく動作しない private static int scoring(String question,Stringanswer) { int length = question.length(); intscore = 2; for (int i = 0; i < length; i++) { (中略:文字が違うたびにscoreを-1して、socreが0以下になったらそのままreturn) } returnscore; }}
C#の入門書を読んでいて、第4章くらいに4ページくらい割いて書いてあるキャスト
( )で変換するのと int.Parse() で変換するのとどう違うのか(どちらか片方でいいのではないか)をネットで調べ、
なんかas とか int.TryParse() とか出てきてあーんー参照型と値型がーになってダウンキャストとポリフォーニズムでお昼ごはんが夜ご飯になったところで切り上げた
型の違う数値同士のときが ( ) で、文字列から数値に変換したいときが int.Parse() とかだな
入門書に書いてあるそのまんまだな
もういいや次ページ行こう全然進まん
では横ですが、ワテクシの特技のRを少々……
eval(parse(text=paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(paste0(
いま、この「はてな匿名ダイアリーの自分の全記事を一括削除するスクリプト」は、動かない?
・POSTに与える最後のcsrf を取ってくるparse が間違って、 rkm= が空になっている。正規表現でparse していたのを直して、 o+XXXXXXXXXXXXXXX/g を拾ってくるようにした。
・POSTに与えるdelete=が元々の %8d%ed%8f%9c%82%b7%82%e9 でも削除できないし、「 %e5%89%8a%e9%99%a4%e3%81%99%e3%82%8b 」でも削除できなかったし、これってマジックナンバーなん?
1. こんな感じで使います。
$pythonparser.py sample.py
importparsercode ='''a = 1 + 1print(a)'''graph =parser.create_graph(code)graph.render("sample")
importastimport sysimportgraphvizdefcreate_graph(lines): graph =graphviz.Graph(format='png')root =ast.parse(lines) node_list = [root] _setup(graph, node_list)return graphdef_setup(graph, node_list):# node node = node_list[-1] node_identity =str(len(node_list)) node_name =type(node).__name__ graph.node(node_identity, node_name)# childrenfor childinast.iter_child_nodes(node): node_list.append(child) child_identity =str(len(node_list)) graph.edge(node_identity, child_identity) _setup(graph, node_list)if __name__ =='__main__': file_name = sys.argv[1]withopen(file_name)asfile: lines =file.read() graph = create_graph(lines) graph.render(file_name)
Facebook はVR の雄 Oculus も買っています。今はVR といえば Oculus ですが、VR にはどんどん大きな会社が参入してきています。近いうちに Oculus の影響力は下がっていくことでしょう。それを見たFacebook の経営層は、Parse と同じ判断をするはずです。その時、Oculus 用のソフトを開発していた人たちは、今のParse で開発していた人たちと同じ辛さを経験するでしょう。これを予見できる開発者たちは、早期に Oculusから撤退するはずです。そうするとVR に対する Oculus の影響力は加速度的に小さくなります。
つまり、何が言いたいかというと、今回の判断は開発者のFacebook 離れを引き起こす判断であり、Facebook に買われたサービスは衰退することを宿命づけてしまった大きな事件の一つだったということです。
Excelを持っているならはてブのJSONデータをそのまま取り込めるそうだからそのデータを使ってブクマが付いた時間のグラフが描けそう。
例えばこんな感じでJSONデータが取れる。http://b.hatena.ne.jp/entry/jsonlite/https://anond.hatelabo.jp/20180315232737
Excel持ってないならスクリプトでCSVにしてしまえばいい。
rubyスクリプトだとこんな感じ。(Mechanize無し版に差し替え。なぜMechanizeを使っていたかと言うとはてブがUser-Agentが空だと値を返してくれないから。ちょっと長くなるが自前でUAを渡すようにした。)
#!/usr/bin/ruby
site =ARGV[0]
json_uri =URI.parse("http://b.hatena.ne.jp/entry/jsonlite/%s" % [site])
response =Net::HTTP.start(json_uri.host,json_uri.port) do |http|
http.get(json_uri.path, "User-Agent" => "Mozilla/5.0")
end
json_data =JSON.parse(response.body)
json_data['bookmarks'].each do |bookmark|
puts [bookmark['user'],bookmark['timestamp'],bookmark['comment'],bookmark['tags'].to_s].to_csv
end
引数に取得したいページのURLを入れる。hatebuapi-csv.rbという名前で保存したとしたらこんな感じで実行。
% hatebuapi-csv.rbhttps://anond.hatelabo.jp/20180315######## > 結果.csv
結構簡単にできた。
ここから、ページ切り替えてURLを収集する処理も追加すれば、
クローロング部分は完成。
require 'nokogiri'
url = 'http://ja.aliexpress.com/category/200003482/dresses.html?spm=2114.52010108.6.7.gT0qlW&addpid=32546825642&isOnSale=yes%22'
charset =nil
end
doc = Nokogiri::HTML.parse(html,nil, charset)
num=0
doc.css('a[class = "product "]').each do |product|
p product.attribute("href").text
p num = num+1
end
skrsvideo
今回プログラミング言語はRubyを選択したため、基本的にはVPS・クラウド的なサーバーでLinuxが動作する環境を探しました。
エロサイトを運営するにあたって問題になるのがサーバー選びです。
基本的に日本のレンタルサーバーではアダルトサイトの運用を禁止しています。
普段使っているさくらのVPSが利用できず、AWSもなんだかグレーな感じ(東京リージョン以外なら・・・?)
そんなわけで探し、GMOグループのWebkeepersを使いました。
使っても良いよ〜というお墨付き、
そして価格も手頃だったためここに決定。
| DB | MariaDB |
|---|---|
| Webサーバ | Nginx |
| フレームワーク | Ruby on Rails |
MariaDBを選んだ理由はなんとなく、MySQLとの違いはほぼありません。利用するGEMもmysql2でいけます。
ちなみにJavaScriptは使わずすべてCSSで作る方針にしました。
スマホ・PC両対応のためにMedia Queryでレスポンシブにしています。
↓
↓
↓
という流れです
gem 'nokogiri'
フロントはhamlとsassで、難しいことはしていないのでcompassはいれませんでした。
あとはデバッグ用にrails_config、pry系が入っています。
skrsvideoでは動画のURLを取得するためにクローラーもどきでスケジューリングして収集しています。
コマンドはこんな感じ
Rakeタスクはnokogiriでxvideosへのリンクを集めています。
doc = Nokogiri::XML(open(URI.parse(url)).read )
urls = []
urls.pushlink[:href] iflink[:href] =~ /xvideos.com\/video(\d+)/
end
Nokogiriのスクレイピングでaタグのリンクを取得し、URLがxvideosのものかチェックして保存って感じです。
動画を探し終えるとaタグからランダムでピックアップし次のページに進んでいきます・
動画が見つかったページはドメインをDBに記録して、しばらくしたら再びクローリングをするようにし、収集の効率化。
30分以上の表示はちょっと頑張ったところ
これはタイトルの文字列から部分一致で引っかかったものを表示しています。
AV女優の名前を表示するためにWikipediaからとってきたら、ちょっと膨大な数になってしまったため断念。
DMMのランキングに載っていた方だけをとりあえず入れています。