AIが生成しがちな「いかにもAIっぽい」日本語の定型表現・水増し・空疎な形容を取り除き、読者の信頼を損なわない自然な文章に直す。記事・原稿・プレスリリース・告知・SNS投稿など、AIの支援を受けて書いた文章を公開前に点検するときに使う。「AI臭を消したい」「文章が機械っぽい」「人が書いたように直したい」などの依頼で使う。
中文简介正在准备中。当前显示原文说明。
SNS・ソーシャルメディアの監視、言説(ナラティブ)の追跡、オープンソース・インテリジェンス(OSINT)を記者向けに支援する。投稿の拡散経路の追跡、組織的キャンペーンや協調的拡散(コーディネートされた非真正な行動)の分析、速報の横断監視、アカウントの真正性・ボット検知、誤情報パターンの把握に使う。
「拡散を追いたい」「ステマ/世論工作を調べたい」「ボットか見分けたい」「炎上を監視したい」などの依頼で使う。
中文简介正在准备中。当前显示原文说明。
实测评分 未实测
查看安装方法安装前可以查看交给 AI 代理的指令内容。
SNS・ソーシャルメディアを報道目的で監視・分析・調査するための体系的な手順とコード集。 記者の問い(何の言説を、どの範囲で、いつまでに追うか)を聞き取り、適切な監視設計・検証・証拠保全を提案する。公開の最終判断と事実確認は記者が行う。
注意:プラットフォームのAPI仕様・料金・利用規約、利用可能なツールは頻繁に変わる。本書の各値・ツールの稼働状況は設計前に最新を確認すること。協調・ボット・真正性のスコアはいずれも仮説(手がかり)であって結論ではない。本スキルは一般的な手引きであり、法的助言ではない。
設計の前に、対象とするサービスの特性を押さえる。
## 日本で監視対象になりやすい場
- X(旧Twitter):日本は世界有数の利用国。速報・炎上・世論工作の主戦場。引用・リポストの連鎖が追跡しやすい
- YouTube/ニコニコ動画:動画・配信・コメント。切り抜き拡散の起点になりやすい
- Instagram/TikTok:画像・短尺動画。発信者特定が難しく、転載・リミックスが多い
- LINE:原則クローズド(個別・グループ)。公開アカウント/オープンチャット以外は取得・監視の対象外
- note・ブログ:長文の言説・一次主張の発生源になりやすい
- 5ch等の掲示板・まとめサイト:匿名。言説の発生・増幅・転載の連鎖を追う対象
- Threads/Bluesky/Mastodon・Misskey等の分散SNS:移行先・避難先として規模拡大
- Telegram:公開チャンネルは閲覧可。非公開グループは対象外
from dataclasses import dataclass, field
from datetime import datetime
from typing import List, Optional, Dict
from enum import Enum
import hashlib
class Platform(Enum):
X = "x" # 旧Twitter。"twitter"は過去データとの互換のため別途扱う
TWITTER = "twitter" # 2023年以前の旧称。レガシーデータ用に保持
FACEBOOK = "facebook"
INSTAGRAM = "instagram"
TIKTOK = "tiktok"
YOUTUBE = "youtube"
NICONICO = "niconico" # ニコニコ動画
THREADS = "threads"
BLUESKY = "bluesky"
MASTODON = "mastodon" # Misskey等の分散SNS含む
TELEGRAM = "telegram"
LINE = "line" # 公開アカウント/オープンチャットのみ
NOTE = "note" # note
BBS = "bbs" # 5ch等の掲示板・まとめ
@dataclass
class SocialPost:
platform: Platform
post_id: str
author: str
content: str
timestamp: datetime
url: str
engagement: Dict[str, int] = field(default_factory=dict)
media_urls: List[str] = field(default_factory=list)
archived_urls: List[str] = field(default_factory=list)
content_hash: str = ""
def __post_init__(self):
# 重複検出のため本文をハッシュ化
self.content_hash = hashlib.md5(
f"{self.platform.value}:{self.content}".encode()
).hexdigest()
@dataclass
class MonitoringQuery:
keywords: List[str]
platforms: List[Platform]
accounts: List[str] = field(default_factory=list)
hashtags: List[str] = field(default_factory=list)
exclude_terms: List[str] = field(default_factory=list)
start_date: Optional[datetime] = None
def to_search_string(self, platform: Platform) -> str:
"""プラットフォーム別の検索クエリ文字列を生成する。"""
parts = []
# キーワード
if self.keywords:
parts.append(' OR '.join(f'"{k}"' for k in self.keywords))
# ハッシュタグ
if self.hashtags:
parts.append(' OR '.join(f'#{h}' for h in self.hashtags))
# 除外語
if self.exclude_terms:
parts.append(' '.join(f'-{t}' for t in self.exclude_terms))
return ' '.join(parts)
日本語特有の注意:表記ゆれ(全角/半角、カタカナ/ひらがな/漢字、長音記号「ー」、伏せ字、隠語)でキーワードが分散する。同義語・別表記・誤変換・スラングを
keywordsに並べる。検索の取りこぼしを前提に、複数クエリで補完する。
from collections import defaultdict
from datetime import datetime, timedelta
class BreakingNewsDetector:
"""キーワード言及の急増(スパイク)を検知する。"""
def __init__(self, baseline_window_hours: int = 24):
self.baseline_window = timedelta(hours=baseline_window_hours)
self.mention_history = defaultdict(list)
def add_mention(self, keyword: str, timestamp: datetime):
"""キーワードの言及を記録する。"""
self.mention_history[keyword].append(timestamp)
# 古いデータを間引く
cutoff = datetime.now() - self.baseline_window * 2
self.mention_history[keyword] = [
t for t in self.mention_history[keyword] if t > cutoff
]
def is_spiking(self, keyword: str, threshold_multiplier: float = 3.0) -> bool:
"""ベースラインを超えて急増しているか判定する。"""
now = datetime.now()
recent = sum(1 for t in self.mention_history[keyword]
if t > now - timedelta(hours=1))
baseline_hourly = len([
t for t in self.mention_history[keyword]
if t > now - self.baseline_window
]) / self.baseline_window.total_seconds() * 3600
if baseline_hourly == 0:
return recent > 10 # 新規トピック用の暫定しきい値
return recent > baseline_hourly * threshold_multiplier
def get_trending(self, top_n: int = 10) -> List[tuple]:
"""スパイクの強さ順にキーワードを返す。"""
spikes = []
for keyword in self.mention_history:
if self.is_spiking(keyword):
recent = sum(1 for t in self.mention_history[keyword]
if t > datetime.now() - timedelta(hours=1))
spikes.append((keyword, recent))
return sorted(spikes, key=lambda x: x[1], reverse=True)[:top_n]
from dataclasses import dataclass
from datetime import datetime
from typing import List, Optional
@dataclass
class AccountAnalysis:
username: str
platform: Platform
created_date: Optional[datetime] = None
follower_count: int = 0
following_count: int = 0
post_count: int = 0
# 真正性のシグナル
profile_photo_is_stock: Optional[bool] = None # アイコンがストック画像/生成画像か
bio_contains_keywords: List[str] = field(default_factory=list)
posts_primarily_reshares: Optional[bool] = None # 投稿の大半がリポスト/転載か
posting_pattern_irregular: Optional[bool] = None # 投稿パターンが不自然か
engagement_ratio_suspicious: Optional[bool] = None # 反応比率が不自然か
def calculate_red_flags(self) -> dict:
"""アカウントの不審点をスコア化する。"""
flags = {}
# アカウントの作成からの経過
if self.created_date:
age_days = (datetime.now() - self.created_date).days
if age_days < 30:
flags['new_account'] = f"作成から{age_days}日"
# フォロワー比率
if self.following_count > 0:
ratio = self.follower_count / self.following_count
if ratio < 0.1:
flags['low_follower_ratio'] = f"比率: {ratio:.2f}"
# 投稿頻度
if self.created_date and self.post_count > 0:
age_days = max(1, (datetime.now() - self.created_date).days)
posts_per_day = self.post_count / age_days
if posts_per_day > 50:
flags['excessive_posting'] = f"1日あたり約{posts_per_day:.0f}件"
# ストック画像/生成画像のアイコン
if self.profile_photo_is_stock:
flags['stock_profile_photo'] = "アイコンがストック/生成画像の疑い"
return flags
def authenticity_score(self) -> int:
"""0〜100。高いほど真正(人間の本人運用)の可能性が高い。"""
score = 100
flags = self.calculate_red_flags()
penalty_per_flag = 20
score -= len(flags) * penalty_per_flag
return max(0, score)
このスコアは手がかり。新規アカウント=偽、ではない(被災時の臨時開設、匿名の内部告発など正当な理由は多い)。必ず人間が裏取りする。
from collections import defaultdict
from typing import Set, Dict
class AccountNetwork:
"""アカウント間の関係を地図化する。"""
def __init__(self):
self.interactions = defaultdict(lambda: defaultdict(int))
self.accounts = {}
def add_interaction(self, from_account: str, to_account: str,
interaction_type: str = "mention"):
"""アカウント間のやり取り(メンション・リポスト等)を記録する。"""
self.interactions[from_account][to_account] += 1
def find_clusters(self, min_interactions: int = 3) -> List[Set[str]]:
"""頻繁にやり取りするアカウント群(クラスタ)を見つける。"""
# 最小しきい値で隣接関係を構築
adjacency = defaultdict(set)
for from_acc, targets in self.interactions.items():
for to_acc, count in targets.items():
if count >= min_interactions:
adjacency[from_acc].add(to_acc)
adjacency[to_acc].add(from_acc)
# 連結成分を探索
visited = set()
clusters = []
for account in adjacency:
if account in visited:
continue
cluster = set()
stack = [account]
while stack:
current = stack.pop()
if current in visited:
continue
visited.add(current)
cluster.add(current)
stack.extend(adjacency[current] - visited)
if len(cluster) > 1:
clusters.append(cluster)
return sorted(clusters, key=len, reverse=True)
def coordination_score(self, accounts: Set[str]) -> float:
"""アカウント群がどれだけ協調的に見えるかをスコア化する。"""
if len(accounts) < 2:
return 0.0
total_possible = len(accounts) * (len(accounts) - 1)
actual_connections = 0
for acc in accounts:
for other in accounts:
if acc != other and self.interactions[acc][other] > 0:
actual_connections += 1
return actual_connections / total_possible if total_possible > 0 else 0
from dataclasses import dataclass, field
from datetime import datetime
from typing import List, Dict, Optional
@dataclass
class Claim:
text: str
first_seen: datetime
first_seen_url: str
variations: List[str] = field(default_factory=list) # 言い換え・派生表現
appearances: List[Dict] = field(default_factory=list)
def add_appearance(self, url: str, platform: Platform,
timestamp: datetime, author: str):
"""この主張が現れた場所を記録する。"""
self.appearances.append({
'url': url,
'platform': platform.value,
'timestamp': timestamp,
'author': author
})
def spread_timeline(self) -> List[Dict]:
"""主張の拡散を時系列で返す。"""
return sorted(self.appearances, key=lambda x: x['timestamp'])
def platforms_reached(self) -> Dict[str, int]:
"""プラットフォーム別の出現数を数える。"""
counts = defaultdict(int)
for app in self.appearances:
counts[app['platform']] += 1
return dict(counts)
def velocity(self, window_hours: int = 24) -> float:
"""拡散速度(直近の1時間あたり出現数)を計算する。"""
if not self.appearances:
return 0.0
recent = [
a for a in self.appearances
if a['timestamp'] > datetime.now() - timedelta(hours=window_hours)
]
return len(recent) / window_hours
言説追跡の要は初出(ペイシェント・ゼロ)の特定。最初に言った人・媒体、最初の改変、最初に大手アカウント/メディアが拾った時点を押さえると、自然拡散か仕掛けられた拡散かの判断材料になる。
from collections import Counter
from datetime import datetime, timedelta
class HashtagAnalyzer:
"""ハッシュタグの使われ方を分析する。"""
def __init__(self):
self.hashtag_posts = defaultdict(list)
def add_post(self, hashtags: List[str], post: SocialPost):
"""投稿のハッシュタグを記録する。"""
for tag in hashtags:
self.hashtag_posts[tag.lower()].append(post)
def co_occurrence(self, hashtag: str, top_n: int = 10) -> List[tuple]:
"""そのタグと一緒に使われやすいタグを見つける。"""
co_tags = Counter()
for post in self.hashtag_posts.get(hashtag.lower(), []):
# 投稿本文からハッシュタグを抽出
tags = [
word.lower() for word in post.content.split()
if word.startswith('#')
]
for tag in tags:
if tag != f'#{hashtag.lower()}':
co_tags[tag] += 1
return co_tags.most_common(top_n)
def posting_pattern(self, hashtag: str) -> Dict:
"""そのタグ付き投稿が現れる時間帯のパターンを分析する。"""
posts = self.hashtag_posts.get(hashtag.lower(), [])
hour_counts = Counter(p.timestamp.hour for p in posts)
day_counts = Counter(p.timestamp.strftime('%A') for p in posts)
return {
'by_hour': dict(hour_counts),
'by_day': dict(day_counts),
'total_posts': len(posts),
'unique_authors': len(set(p.author for p in posts))
}
日本語のハッシュタグは単語が空白で区切られないため、
post.content.split()だけでは抽出漏れが出る。正規表現(例#[^\s##、。,.]+、全角#も対象)で拾うと精度が上がる。時間帯分析は時刻が日本時間(JST)か確認する(APIはUTC返却が多い)。
レート制限・一括処理・壊れたアーカイブUIからの復旧など、本格的なアーカイブ手順は web-archiving(ウェブアーカイブ) スキルを参照。
import re
import requests
from datetime import datetime
from typing import Optional
from urllib.parse import quote, urljoin
class SocialArchiver:
"""削除される前にソーシャル投稿をアーカイブする。"""
def __init__(self):
self.archived = {}
def archive_to_wayback(self, url: str) -> Optional[str]:
"""URLをInternet Archive(Wayback Machine)に送る。
匿名保存は毎分15件程度に制限され、有料記事や重いJS描画ページは
黙って取りこぼすことがある。大量に保存するなら Internet Archive の
S3キーを登録し、Authorization ヘッダを付ける。
"""
try:
save_url = f"https://web.archive.org/save/{quote(url, safe='')}"
response = requests.get(save_url, timeout=30)
if response.status_code == 200:
archived_url = response.url
self.archived[url] = {
'wayback': archived_url,
'archived_at': datetime.now().isoformat(),
}
return archived_url
except Exception as e:
print(f"Waybackへの保存に失敗: {e}")
return None
def archive_to_archive_today(self, url: str) -> Optional[str]:
"""URLをarchive.todayに送る。
運用上の注意(2026年時点):archive.todayは運営者特定をめぐる法的圧力や、
引用ソースとしての信頼性低下が報じられている。Wayback Machineで
描画できないページの保全には依然有用だが、Internet Archiveを主、
本サービスを従とし、依拠した場合はその旨を記録する。スクレイパーには
CAPTCHAを返し、レート制限も厳しい。
"""
try:
response = requests.post(
'https://archive.today/submit/',
data={'url': url, 'anyway': '1'},
timeout=60,
allow_redirects=False,
headers={'User-Agent': 'Mozilla/5.0 (verification archive bot)'},
)
# archive.todayはスナップショットURLを次の2通りで返す:
# - 30x で Location: https://archive.today/<snapshot_id>
# - 200 で Refresh: 0;url=https://archive.today/<snapshot_id>
# リダイレクトを黙って追うと /wip/ ページに着いたり正規URLを
# 見失うので、両方のヘッダを明示的に処理する。
if response.status_code in (301, 302, 303, 307, 308):
location = response.headers.get('Location')
if location:
# Locationは相対URLのことがある(RFC 7231)。リクエストURL基準で解決。
return urljoin(response.url, location)
if response.status_code == 200:
refresh = response.headers.get('Refresh', '')
# Refreshのキーワードは大文字小文字を区別しない。;区切りのパラメータを含む
# ことがあるので url= 指示子そのものを拾う。
m = re.search(r'\burl\s*=\s*(.+)', refresh, re.IGNORECASE)
if m:
target = m.group(1).strip().strip('\'"')
return urljoin(response.url, target)
except Exception as e:
print(f"archive.todayへの保存に失敗: {e}")
return None
def full_archive(self, url: str) -> dict:
"""冗長化のため複数サービスにアーカイブする。"""
results = {
'original_url': url,
'archived_at': datetime.now().isoformat(),
'archives': {},
}
wayback = self.archive_to_wayback(url)
if wayback:
results['archives']['wayback'] = wayback
archive_today = self.archive_to_archive_today(url)
if archive_today:
results['archives']['archive_today'] = archive_today
return results
公開アーカイブに送るのは公開投稿のみ。非公開・限定公開の内容を公開アーカイブに送らない。非公開の素材(取材源提供のエクスポート、限定公開URL等)は、タイムスタンプ付きスクリーンショットや画面録画で保全し、ハッシュ値を取り、各社の証拠保全規程に従って保管する。投稿時刻・取得時刻・取得経路を必ず併記する。
## 協調的な非真正行動(ステマ・世論工作・雇われ拡散)の指標
### タイミングのパターン
- [ ] 複数アカウントが同じ内容を数分以内に投稿
- [ ] 複数アカウントで投稿時刻が同期している
- [ ] 一斉に活動した後に沈黙する(バースト→休眠)
- [ ] 人間の入力速度を超える速さで投稿が出る
### 内容のパターン
- [ ] 複数アカウントで本文が同一・ほぼ同一
- [ ] 同じ画像・動画を複数アカウントが共有
- [ ] 同じ誤字・同じ書式崩れが共通
- [ ] コピペの痕跡(不自然な改行・残った定型文)
### アカウントのパターン
- [ ] 作成時期が近い
- [ ] 命名規則が似ている(名前+数字の連番など)
- [ ] アイコンが汎用画像・ストック画像・生成画像
- [ ] 個人的な投稿がほぼ無く、共有・転載が中心
- [ ] 同じアカウント群をフォローしている
- [ ] 互いに不自然に多く反応し合う
### ネットワークのパターン
- [ ] ネットワーク分析で密なクラスタを形成
- [ ] 同じ外部ソースを一斉に増幅
- [ ] 同じアカウント・同じハッシュタグを標的にする
- [ ] プラットフォームをまたいだ連動が見える
def coordination_likelihood(posts: List[SocialPost]) -> dict:
"""投稿群が協調的な活動である可能性をスコア化する。"""
if len(posts) < 2:
return {'score': 0, 'signals': []}
signals = []
score = 0
# 本文の重複をチェック
contents = [p.content for p in posts]
unique_contents = set(contents)
if len(unique_contents) < len(contents) * 0.5:
signals.append("本文の重複が多い")
score += 30
# 投稿タイミングの集中をチェック
timestamps = sorted(p.timestamp for p in posts)
rapid_posts = 0
for i in range(1, len(timestamps)):
if (timestamps[i] - timestamps[i-1]).seconds < 60:
rapid_posts += 1
if rapid_posts > len(posts) * 0.3:
signals.append("投稿時刻が不自然に集中")
score += 25
# 投稿者の数をチェック
authors = set(p.author for p in posts)
if len(authors) > 5 and len(contents) / len(authors) > 2:
signals.append("少人数の投稿者が似た投稿を多数")
score += 20
return {
'score': min(100, score),
'signals': signals,
'posts_analyzed': len(posts),
'unique_authors': len(authors)
}
留意:公式RTやテンプレ拡散の呼びかけ、災害時の定型注意喚起など、正当な一斉投稿も同じシグナルを示す。高スコア=工作、と即断しない。スコアは取材の出発点。
2026年時点の状況。プラットフォームのAPIは頻繁に変わる。設計前に料金・アクセス可否を必ず確認すること。
Xが記事の中心になるときは、分析や執筆の前に「ソースパケット」を組み立てる。
ここで出る協調スコア・ボットスコア・真正性ラベルは、人間が根拠を確認するまでは結論ではなく手がかりとして扱う。
| プラットフォーム | 調査向けアクセス | 注意 |
|---|---|---|
| X(旧Twitter) | 従量課金の開発者API(developer.x.com)/X Pro Search(X Premium+の一般向け機能)/Brandwatch・Sprinklr等の有料サードパーティ | 無料の学術・研究枠は2023年初頭に終了。2024年のBasic/Proの月額層は、2026年2月に従量課金(API呼び出し単位の課金、月額なし)へ置換。単価・レート上限は開発者ポータルで要確認。2023年以降の規約はスクレイピングを明示的に禁止 |
| Facebook/Instagram | Meta Content Library+同API(研究アクセス)/Junkipedia(無料・報道向け)/NewsWhip(有料) | CrowdTangleは2024年8月14日に完全終了。Meta Content Libraryが後継。申請はMetaのポータルで直接。適格性は学術・非営利の研究者が中心で、実務記者は所属機関を通じてのみ通ることが多い |
| TikTok | Research API(適格な学術・非営利研究者/EUではDSAで認証された研究者)/Exolyt・Pentos(有料) | developers.tiktok.comで申請。EU拠点の研究者はDSA第40条で相対的に強いアクセスを持つ |
| YouTube | YouTube Data API v3 | 既定で1日10,000ユニット(検索は100ユニット=1日約100検索)。増枠は申請制で審査に数週間。報道専用枠は無い |
| Reddit API(非営利研究は無料)/Arctic Shift(Pushshiftの後継、無料) | Pushshiftは2023年以降、認証モデレーター限定で報道用途には使えない。Arctic Shiftが現行の後継 | |
| Bluesky | Jetstream(WebSocket上のフィルタ済みJSON、認証不要)/生Firehose | 既定で公開。Jetstreamが報道向けの入口(フィルタ済みで約850MB/日)。生Firehoseは4〜8GB/時で自前のアーカイブ構築が必要 |
| Threads(Meta) | Threads API(投稿・埋め込み用)/Meta Content Library(研究用) | 一括の過去データ研究はMeta Content Library経由で、学術中心の制限は同じ |
| Mastodon/Misskey等の分散SNS | 各インスタンスの公開タイムラインAPI/横断検索(search.noc.social等) | 多くのインスタンスが未認証APIアクセスを禁止。管理者の設定次第。横断検索は断片的 |
| Telegram | Bot API+MTProto+公開プレビュー(t.me/s/<channel>)/Bellingcatのツール群 | 公開チャンネルの取得は多くの法域で適法。非公開グループは対象外 |
| LINE | Messaging API(自社公式アカウント運用向け)/公開アカウント・オープンチャットの閲覧 | 個別トーク・グループ・通常のオープンチャットは取得・監視の対象外。原則クローズドとして扱う |
| note・ブログ | 公開ページの閲覧/各サービスの提供範囲 | 専用の研究APIは一般に無い。長文の一次主張の発生源として個別に確認 |
| 5ch等の掲示板・まとめ | 公開スレッドの閲覧/各サイトの規約 | 匿名。発生・増幅・転載の連鎖を追う対象。発信者特定は法・倫理に従い慎重に |
💡 無料で拡散分析ができる現実解は Bluesky(日本版・検証済みメモ 2026-07)。 X は無料では拡散分析が事実上できない(開発者APIは従量課金、fxtwitter/vxtwitter は単一投稿の取得に限られる)。 一方 Bluesky は公開REST
https://api.bsky.app(認証不要・無料) で検索〜スレッド取得ができ、時系列・発信者・協調・真正性の分析に十分使える。 実測メモ:app.bsky.feed.searchPosts等の公開エンドポイントはapi.bsky.appを使う(public.api.bsky.appはWAFで403になることがある)。 ただし Blueskyは日本の代表的世論とはズレる(利用者層が偏る)ため、Xでの現象の代理として使うときは代表性の限界を明記する。 なお、ここで出る協調・ボット・真正性のスコアは手がかりであって結論ではない(例:通信社アカウントが「高頻度投稿」で真正性フラグに触れることがある=高頻度≠ボット)。
EUのデジタルサービス法(DSA)は、EU拠点の研究者にTikTokやMetaプラットフォームへの強いアクセス権を与えている。日本にはこれと同等の研究者アクセス制度は現状ない(要確認)。日本の記者がResearch API層を使うには、EUの研究機関・認証研究NPOといった連携先が必要になる場合がある。これは抜け道ではなく正規の経路。日本国内では、各社の所属・学術連携・データ事業者契約を通じてアクセスを確保するのが現実的。
上のPython製ヒューリスティックは、監視とパターンの当たりをつけるための出発点。本格的なOSINT実務では、次の定番外部ツールを使う(多くは国際的に利用可能。利用前に稼働状況と利用規約を確認)。
注:米国の選挙偽情報研究を担っていた一部機関は2024年に再編された。研究の所在は流動的なので、引用前に各機関の現況を確認すること。
SNS分析は、対象者の権利と取材の自由の両方に関わる。次を踏まえる(いずれも一般的な留意点であり、具体の判断は法務・デスクと相談する)。
## 押さえるべき主な論点(要確認・法的助言ではない)
### 個人情報の保護
- 個人情報保護法:SNSから個人情報を収集・蓄積・分析する行為は、報道目的なら適用除外の余地があるが、
自社の規程と必要最小限の原則に従う。収集の目的・範囲・保管期間を決めておく
- 公開情報でも、名寄せ・プロファイリングで「特定の個人」を浮かび上がらせる場合は配慮が必要
### 名誉毀損・信用毀損・侮辱
- 投稿の引用・要約で個人や法人の社会的評価を下げる表現は、名誉毀損(刑法230条・民法709条)等のリスク。
真実性・公益性・公共性の要件、相当性(裏取り)を満たすかをデスク・法務と確認
- 「ボット」「工作員」「ステマ」と断定的にラベリングしない。スコアは仮説であり、断定は別途の立証が要る
### プライバシー・肖像
- 一般私人の私生活上の事実・写真の扱いは慎重に。公人/私人、公共の関心事かを区別する
- 未成年・被害者・遺族・病歴等の機微情報は特に配慮
### 発信者の特定
- 匿名アカウントの発信者特定は、プロバイダ責任制限法の発信者情報開示など法的手続の領域。
推測での特定・暴露(個人情報の晒し)はしない
### 著作権・利用規約
- 投稿本文・画像・動画の転載は著作権法に触れうる。引用の要件(必然性・主従関係・出所明示)を守る
- 各プラットフォームの利用規約(特にスクレイピング禁止)を守る。規約違反の取得は証拠価値も損なう
### 取材倫理
- なりすましアカウントや偽装での潜入はしない(後述の倫理ガイドライン)
- 取材源がSNS内容を提供した場合、その人を危険に晒さない
| 項目 | 値 |
|---|---|
| version | 1.1.0(日本語版) |
| 原典 version | 1.1.0 |
| 原典 created | 2025-12-26 |
| 原典 updated | 2026-06-18 |
| author | Joe Amditis(原典)/日本語ローカライズ版 |
| domain | journalism, osint |
| complexity | advanced |
本スキルは claude-skills-journalism(by Joe Amditis, MIT License, © 2025 Joe Amditis,
https://github.com/jamditis/claude-skills-journalism )の journalism-core/skills/social-media-intelligence を
原典の構成(リアルタイム監視・アカウント分析・言説追跡・証拠保全・協調検知・プラットフォーム別取得手段・OSINTツール・倫理)に沿って日本語化し、
日本語プラットフォーム環境と個人情報保護法・名誉毀損・プライバシー・取材倫理に再構成したものです。
米国・EU固有の制度(EU DSA第40条等)はその旨を注記し、日本に同等制度が無いものはその旨を明記しています。
コードはコメントのみ日本語化し機能は保持しています。Botometer・Hoaxy・Bellingcat等の外部ツール名は事実情報として参照しているだけで、各ツールの本文・著作物は転載していません。
原典の著作物本文は転載していません。原作者の公認・推奨を受けたものではありません。
MIT ライセンス全文は同梱の LICENSE-MIT.txt を参照。
还没有评价。欢迎分享你的使用感受。
无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。
还没有评论。来写第一条吧。
AIが生成しがちな「いかにもAIっぽい」日本語の定型表現・水増し・空疎な形容を取り除き、読者の信頼を損なわない自然な文章に直す。記事・原稿・プレスリリース・告知・SNS投稿など、AIの支援を受けて書いた文章を公開前に点検するときに使う。「AI臭を消したい」「文章が機械っぽい」「人が書いたように直したい」などの依頼で使う。
中文简介正在准备中。当前显示原文说明。
取材・調査・データ報道で使える無料データ源(API)のカタログ。政府統計(e-Stat)、地域経済(RESAS)、気象(気象庁)、法令(e-Gov)、企業開示(EDINET)、書誌・国会会議録(国立国会図書館)、地理空間(国土地理院)、汎用の国際API(GDELT・Open-Meteo・Wayback等)を用途別に整理し、登録要否・利用条件・選び方を示す。「無料のデータ源が欲しい」「このテーマのAPIは?」「公的データをプログラムで取りたい」といった依頼で使う。
中文简介正在准备中。当前显示原文说明。
データ報道(データジャーナリズム)の手順を支援する。データセットの分析、グラフや地図の作成、雑然としたデータのクリーニング、統計の算出、データに基づく記事の構築に使う。「e-Statのデータを分析したい」「人口あたりで比較したい」「グラフが誤解を招かないか確認したい」「統計から記事を組み立てたい」などの依頼で使う。記者・編集者・調査担当向け。
中文简介正在准备中。当前显示原文说明。
取材で集めた資料(開示文書・記事・SNS・反訳など)をデジタルアーカイブ化し、AIで要約・分類・エンティティ抽出・関係づけ(知識グラフ化)して横断検索できる調査基盤を作るための手引き。「取材資料を整理したい」「大量の開示文書をデータベース化したい」「人物・組織・出来事の関係を可視化したい」「調査報道のアーカイブを作りたい」などの依頼で使う。
中文简介正在准备中。当前显示原文说明。
発言・記事・SNS投稿などの主張を体系的にファクトチェックする。主張の抽出、検証可能な命題への分解、根拠の収集、当事者への確認、判定(レーティング)、記録、訂正対応までを支援する。掲載前の裏取り、ファクトチェック記事の作成、編集部の検証手順づくりに使う。「ファクトチェックして」「この発言は本当か」「裏取りの手順を」などの依頼で使う。
中文简介正在准备中。当前显示原文说明。
テキスト・記事・ウェブページの内容を、厳密な検証方法論にもとづいてファクトチェックする。検証可能な主張を抽出し、信頼できる一次情報・公的データ・検証機関と突き合わせ、各主張の真偽と確からしさ(確信度)、情報源の信頼度スコアを評価し、根拠つきの検証レポートにまとめる。「この主張を検証して」「記事をファクトチェックして」「情報源の信頼性を見て」「真偽を判定して」「誤情報か確かめて」などの依頼で使う。付属の references(信頼できる情報源/検証方法論)を参照する検証重視版。
中文简介正在准备中。当前显示原文说明。