![sed を使用して RSS アイテムをフィルタリングする](https://rvso.com/image/1605160/sed%20%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%20RSS%20%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0%E3%82%92%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%99%E3%82%8B.png)
次のようなスクリプトを書きたいと思います:
- RSSフィードURLを入力として受け取ります
- フィードをダウンロードする
- タグが正規表現と一致しないすべての
<item> ...</item>
出現を削除します。title
次の例でこれを説明します。次の 3 つの項目を含む RSS フィードがあるとします。
- Project Foo - 始めましょう!
- まったく別のもの
- Project Fooの最新情報
タイトルに「Project Foo」が含まれるアイテムのみを保持したいと思います。
入力ファイルの例:
<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0">
<channel>
<title>My glorious newsfeed</title>
<description>...</description>
<link>...</link>
<language>...</language>
<pubDate>...</pubDate>
<item>
<title>Project Foo - Let's get started!</title>
<link>...</link>
<description>...</description>
<pubDate>...</pubDate>
</item>
<item>
<title>Something else entirely</title>
<link>...</link>
<description>...</description>
<pubDate>...</pubDate>
</item>
<item>
<title>Another update on Project Foo</title>
<link>...</link>
<description>...</description>
<pubDate>...</pubDate>
</item>
</channel>
</rss>
出力ファイルの例:
<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0">
<channel>
<title>My glorious newsfeed</title>
<description>...</description>
<link>...</link>
<language>...</language>
<pubDate>...</pubDate>
<item>
<title>Project Foo - Let's get started!</title>
<link>...</link>
<description>...</description>
<pubDate>...</pubDate>
</item>
<item>
<title>Another update on Project Foo</title>
<link>...</link>
<description>...</description>
<pubDate>...</pubDate>
</item>
</channel>
</rss>
可能であれば、 のようなツールは使わずにpython
、コマンドライン ツールで実行したいのですが、私はsed
などの使用にまったく慣れていないので、助けが必要です :)
これまでのところ、次のものがあります:
cat sample-feed.xml \
| tr -d '\n' \
| sed $'s/\<item\>/\\\n\<item\>/g;s/\<\/channel\><\/rss\>/\\\n\<\/channel\><\/rss\>/g' \
| sed '/^\<item\>/ d'
まず、改行をすべて削除します。次に、改行を追加して、各行を<item>...</item>
独自の行にします。最後のコマンドは、で始まるすべての行を削除します<item>
。
結果は、アイテムのない有効な RSS フィードになります。
<?xml version="1.0" encoding="iso-8859-1"?><rss version="2.0"><channel><title>My glorious newsfeed</title><description>...</description><link>...</link><language>...</language><pubDate>...</pubDate>
</channel></rss>
これをローカル ファイルではなく URL で動作させるには、cat sample-feed.xml
を に置き換えるだけですcurl -s <some url>
。
ただし、まだ不足しているのは、「Project Foo」で始まるが「Project Foo」を含まないsed '/^\<item\>/ d'
行のみを削除するコマンドの変更です。<item>
したがって、最後の行に何を書くべきかを教えていただければ、とてもうれしいです。一方で、これを行うにはもっとエレガントな方法があるはずです。私が見た限りでは、これは非常に強力で、1 つのコマンドsed
で実行できるはずです。sed
回答をお待ちしています:-)
答え1
コメントで提案されているように、xmlstarlet
これを解決するために使用してみましたが、うまくいきました。これが私のスクリプトです
xml ed -d '//item[not(contains(title,"Project Foo"))]' < sample_rss.xml
フィード コンテンツがファイル にあると仮定しますsample_rss.xml
。そのコンテンツは にフィードされ、指定された XPath 式に一致するすべてのメモが削除されます。XPath 式は、テキスト を含む ノードを持たない をxml ed -d
検索します。<item>
<title>
"Project Foo"
これはうまく機能しているようで、実行時間にも非常に満足しています。
real 0m0.003s
user 0m0.001s
sys 0m0.002s
名前空間に注意
これを適切な RSS フィードまたは Atom フィードで動作させたい場合、 YouTube の次の例のように、feed
に XML 名前空間 ( ) 属性が含まれていることに気付くでしょう。xmlns
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns:yt="http://www.youtube.com/xml/schemas/2015" xmlns:media="http://search.yahoo.com/mrss/" xmlns="http://www.w3.org/2005/Atom">
...
</feed>
そうすると、上記のスクリプトは動作しなくなります。これを修正するのにかなり頭を悩ませましたが、動作させる方法は次のとおりです。
xml ed -d '//_:entry[not(contains(_:title,"Project Foo"))]' < youtube_rss.xml
この名前空間の問題の詳細については、こちらをご覧ください。http://xmlstar.sourceforge.net/doc/UG/ch05.html