Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RSSフィードをもっと便利に / Make RSS feeds more convenient #camphor_lt

7f68f5f85f4a39df7d8d3c81cbbfb788?s=47 ぷらす
August 08, 2020

RSSフィードをもっと便利に / Make RSS feeds more convenient #camphor_lt

CAMPHOR- LT 2020 Summerの発表スライドです。

https://camphor.connpass.com/event/182978/

7f68f5f85f4a39df7d8d3c81cbbfb788?s=128

ぷらす

August 08, 2020
Tweet

Transcript

  1. 344ϑΟʔυΛ΋ͬͱศརʹ $".1)03 -54VNNFS /BPLJ,JTIJ !QBTT 

  2. ؛ ௚ً ΀Β͢ 5XJUUFSQBTT (JU)VCQBTT ࣗݾ঺հ  l $".1)03 ୅ද

    l αʔόαΠυϝΠϯ l (P 5ZQF4DSJQU એ఻ ࠷ۙ3FMBZN͍ͬͯ͏8FCαʔϏ ε࡞Γ·ͨ͠ IUUQTSFMBZNDBNQIOFU
  3. 344஌ͬͯΔਓʁ 

  4. 344 3FBMMZ4JNQMF4ZOEJDBUJPO l χϡʔε΍ϒϩάͳͲ֤छͷ΢ΣϒαΠτͷߋ৽৘ใΛ ഑৴͢ΔͨΊͷจॻϑΥʔϚοτͷ૯শ l YNMܗࣜͳͷͰϓϩάϥϜͰ؆୯ʹύʔεग़དྷΔ  IUUQTKBXJLJQFEJBPSHXJLJ344

  5. 344ͷϢʔεέʔε  l ༷ʑͳςοΫϒϩάͷهࣄΛ344Ϧʔμʔʹొ࿥ͯ͠ಡΉ l ͸ͯͳϒϩά΍2JJUB͸σϑΥϧτͰରԠͯ͠Δ l ($1ͷϦϦʔεϊʔτΛ4MBDLʹྲྀ͢ l :PV5VCFνϟϯωϧͷߋ৽Λ344ͰνΣοΫ͢Δ

    l IUUQTXXXZPVUVCFDPNGFFETWJEFPTYNM DIBOOFM@JE6$UK+ H$I-RF571BEJE4X ৘ใऩूʹ޲͍ͨن֨
  6. 344Ϧʔμʔ'FFEMZ 

  7. 344ͷਏΈ l ྲྀΕͯ͘Δ৘ใ͕ଟ͗͢Δ l BTDJJKQͳͲͷχϡʔεαΠτΛߪಡ͢Δͱ͍ͬͺ͍ྲྀΕͯ͘Δ l ͦ΋ͦ΋344ʹରԠ͍ͯ͠ͳ͍αΠτ͕݁ߏ͋Δ l ΞʔςΟετͷ)1ͳͲ 

  8. 344Λྑ͍ײ͡ʹѻ͏ϥΠϒϥϦΛ࡞੒͠·ͨ͠ QBTTGFFEFS 344 "UPN BOE+40/GFFEHFOFSBUPSGSPN NVMUJQMF344 "UPN BOEBOZFOUSJFTZPVXBOU 

  9. GFFEFSͰग़དྷΔ͜ͱ  l 344ͷهࣄΛϑΟϧλͯ͠৽ͨͳ344Λ࡞੒ l ෳ਺ͷ344ΛϚʔδͯ̍ͭ͠ͷ344Λ࡞੒ l ग़ྗ͸344͚ͩͰͳ͘ɺ"UPN΍+40/ʹ΋ରԠ l ಠࣗʹJOUFSGBDFΛຬͨ͢ߏ଄ମΛ࡞Δ͜ͱͰɺ

    ೚ҙͷαΠτͷ৘ใ͔ΒϑΟʔυΛ࡞੒
  10. GFFEFSͷجຊతͳ࢖͍ํ  import "github.com/p1ass/feeder" rss1 := feeder.NewRSSCrawler("https://example.com/rss1") // ここでRSSのURLを指定 rss2

    := feeder.NewRSSCrawler("https://example.com/rss2") items, _ := feeder.Crawl(rss1, rss2) // 複数のRSSから記事を取得 feed := &feeder.Feed{ // 新規のフィードを作成 Title: "My feeds", Created: time.Now(), Items: items, // 2つのRSSから取得した記事を新規で作成するフィードに追加 } json, _ := feed.ToJSON() // string rssReader, _:= feed.ToRSSReader() // io.Reader ޙ͸)551Ͱ഑৴͢Ε͹0,
  11. GFFEFSͷجຊతͳ࢖͍ํ  import "github.com/p1ass/feeder" rss1 := feeder.NewRSSCrawler("https://example.com/rss1") // ここでRSSのURLを指定 rss2

    := feeder.NewRSSCrawler("https://example.com/rss2") items, _ := feeder.Crawl(rss1, rss2) // 複数のRSSから記事を取得 feed := &feeder.Feed{ // 新規のフィードを作成 Title: "My feeds", Created: time.Now(), Items: items, // 2つのRSSから取得した記事を新規で作成するフィードに追加 } json, _ := feed.ToJSON() // string rssReader, _:= feed.ToRSSReader() // io.Reader ޙ͸ੜ੒ͨ͠344ͳΓ+40/Λฦ͢)551αʔόΛ࡞੒͢Ε͹0, ϑΟϧλ͍ͨ͠ͳΒ TMJDF͔Βཉ͍͠෺Λ நग़͢Δؔ਺Λ ڬΊ͹0,
  12. Ԡ༻ྫϙʔτϑΥϦΦʹ༷ʑͳഔମͷهࣄΛදࣔ GFFEFSͰࣗ࡞ϒϩάͱ2JJUBͷهࣄΛ$SBXMͯ͠+40/"1*ΛݐͯͯΔ 

  13. ٕज़తͳ࿩ l ݴޠ(P l ϥΠϒϥϦ࡞੒౰࣌ษڧͯ͠Δݴޠͩͬͨ l JP3FBEFSΠϯλʔϑΣʔεΛຬ͍ͨͯ͠Δ l (PͰ࠷΋࢖ΘΕΔΠϯλʔϑΣʔεͷ̍ͭ l

    ͋ΒΏΔೖग़ྗΛந৅Խͯ͠ѻ͑Δ l JP8SJUFSΛຬͨ͢ϑΝΠϧ΍)551ͷϨεϙϯεͳͲʹ؆୯ʹίϐʔͰ ͖Δ  type Reader interface { Read(p []byte) (n int, err error) } IUUQTHPMBOHPSHQLHJP3FBEFS
  14. ೚ҙͷαΠτͷ৘ใ͔ΒϑΟʔυΛ࡞੒ ΠϯλʔϑΣʔεΛຬͨ͢ߏ଄ମΛ࡞ͬͯGFFEFS$SBXMؔ਺ʹ౉͚ͩ͢ type Crawler interface { Crawl() ([]*Item, error) }

    
  15.  func (crawler *SamasoniCrawler) Crawl() (*feeder.Items, error) { query :=

    url.Values{} query.Add("perform_id", "85895") query.Add("sort_key", "sale_start_at") query.Add("sort_order", "asc") res, err := http.Get(crawler.url + "?" + query.Encode()) if err != nil { return nil, errors.New("failed to get html document") } defer res.Body.Close() doc, err := goquery.NewDocumentFromReader(res.Body) if err != nil { return nil, errors.New("failed to read from response body") } sec := doc.Find("div#tickets").Find("div.list-ticket") items := &feeder.Items{} sec := doc.Find("div#tickets").Find("div.list-ticket") items := &feeder.Items{} sec.Each(func(index int, s *goquery.Selection) { if s.HasClass("list-ticket") { title := s.Find("h2").Find("a").Text() path, _ := s.Find("h2").Find("a").Attr("href") t := time.Now() item := &feeder.Item{ Title: title, Link: &feeder.Link{ Href: "https://tiketore.com" + path, Rel: "", Type: "", Length: "",}, Id: path, Created: &t, } items.Items = append(items.Items, item) } }) return items, nil } ྫνέοταΠτΛΫϩʔϧ
  16. ·ͱΊ l 344͸΢ΣϒαΠτͷߋ৽৘ใΛ഑৴͢ΔͨΊͷจॻϑΥʔϚοτͷ ૯শ l QBTTGFFEFSΛ࢖͏͜ͱͰɺ೚ҙͷ৘ใ͔Β344΍+40/Λ࡞੒Ͱ ͖Δ l ഑৴͢ΔهࣄΛϓϩάϥϜͰࣗ༝ʹૢ࡞Ͱ͖Δ l

    Ԡ༻ྫ͸਺͑੾Εͳ͍΄Ͳ୔ࢁʂ l 4POZ.VTJDͷ:PV5VCFνϟϯωϧ͔Βʮถ௡ݰࢣʯͷಈը͚ͩநग़ l ྑ͔ͬͨΒ࢖ͬͯΈ͍ͯͩ͘͞ ͦͯ͠4UBS⭐΋͍ͩ͘͞