回精華區
作者itoc.bbs@processor.tfcis.org (核心動力) 看板: plan
標題Re: 請問關於雅虎!奇摩的新聞功能
時間動力核心 (2004/02/12 Thu 12:45:28) Updated: 2006/05/23
※ 引述《segaa.bbs@segaa.com.tw (加班ing)》之銘言:
>    如果說要像無名一樣直接把kimo新聞自動轉到看板上
>    每個分類各開一個版,每天自動執行去抓新聞後直接post到板上

  在 ~/run/kimo 下開 12 個目錄,分別是
  A/ B/ C/ D/ E/ F/ G/ H/ I/ J/ K/ L/

  亦即在工作站上執行以下指令
  % mkdir ~/run/kimo
  % mkdir ~/run/kimo/A ~/run/kimo/B ~/run/kimo/C ~/run/kimo/D
  % mkdir ~/run/kimo/E ~/run/kimo/F ~/run/kimo/G ~/run/kimo/H
  % mkdir ~/run/kimo/I ~/run/kimo/J ~/run/kimo/K ~/run/kimo/L

: src/util/Makefile

EXE =   .... enews-open

: crontab -e 新增此二行

# 每天 10:30AM 4:30PM 抓奇摩新聞
30 10,16 * * * bin/enews-open

: struct.h 新增下面這段

/* ----------------------------------------------------- */
/* enews-open.c 中運用的資料結構 : 256 bytes             */
/* ----------------------------------------------------- */


typedef struct
{
  time_t chrono;                /* 編號 */
  char kind;                    /* 種類 */
  char xname[50];               /* 檔案名稱 */

  char link[128];               /* 連結路徑 */
  char title[TTLEN + 1];        /* 文章標題 */
} ENEWS;

: util/enews-open.c 新增此程式

/*-------------------------------------------------------*/
/* util/enews-open.c    ( NTHU CS MapleBBS Ver 3.10 )    */
/*-------------------------------------------------------*/
/* target : 奇摩新聞更新                                 */
/* create : 02/01/29                                     */
/* update :   /  /                                       */
/* author : itoc.bbs@bbs.tnfsh.tn.edu.tw                 */
/*-------------------------------------------------------*/


#if 0

 本奇摩新聞更新程式需要配合 contab 去抓資料,crontab 如下:

# 每天 10:30AM 4:30PM 抓奇摩新聞
30 10,16 * * * bin/enews-open

 要使用 enews-open.c 必須裝有 lynx,注意 lynx 的路徑要和程式吻合。
 如果主機需透過 proxy 才能連外的話,那麼要修改 lynx.cfg 的 http_proxy 設定值。

 文章檔案放在 run/kimo/

 資料來源:Yahoo! 奇摩新聞 http://tw.news.yahoo.com/

#endif


#include "bbs.h"


#define LYNX_PATH       "/usr/local/bin/lynx --source"  /* lynx 的絕對路徑 */


#define INDEX_FILE  "tmp/kimo_index"
#define NEWS_FILE   "tmp/kimo_news"

#define YAHOO_URL   "http://tw.yahoo.com/me/news/*http://tw.news.yahoo.com/"


/*-------------------------------------------------------*/
/* 文章轉到看板                                          */
/*-------------------------------------------------------*/


static BCACHE *bshm;


static void
init_bshm()
{
  /* itoc.030727: 在開啟 bbsd 之前,應該就要執行過 account,
     所以 bshm 應該已設定好 */

  bshm = shm_new(BRDSHM_KEY, sizeof(BCACHE));

  if (bshm->uptime <= 0)        /* bshm 未設定完成 */
    exit(0);
}


static void
update_btime(brdname)
  char *brdname;
{
  BRD *bhdr, *tail;

  bhdr = bshm->bcache;
  tail = bhdr + bshm->number;
  do
  {
    if (!str_cmp(brdname, bhdr->brdname))
    {
      bhdr->btime = -1;
      break;
    }
  } while (++bhdr < tail);
}


static int                      /* 1: 以前就抓過的連結 */
old_link(fold, link)
  char *fold;
  char *link;
{
  int rc = 0;
  ENEWS enews;
  FILE *fp;

  if (fp = fopen(fold, "r"))
  {
    while (fread(&enews, sizeof(ENEWS), 1, fp) == 1)
    {
      if (!strcmp(enews.link, link))
      {
        rc = 1;
        break;
      }
    }

    fclose(fp);
  }

  return rc;
}


static void
post_board(fpath, title, kind)
  char *fpath;
  char *title;
  char kind;
{
  char folder[64];
  HDR hdr;
  char class[12][5] =
  {
    "政治", "社會", "國際", "兩岸", "財經", "影視",
    "體育", "生活", "休閒", "健康", "科技", "新奇"
  };
  char *board = "KimoNews";    // 轉去 KimoNews 板,自定 

  brd_fpath(folder, board, FN_DIR);
  hdr_stamp(folder, HDR_COPY | 'A', &hdr, fpath);
  strcpy(hdr.owner, STR_SYSOP);
  strcpy(hdr.nick, SYSOPNICK);
  sprintf(hdr.title, "[%s] %.64s", class[kind - 'A'], title);
  rec_add(folder, &hdr, sizeof(HDR));

  update_btime(board);
}


/*-------------------------------------------------------*/
/* 分析 html                                             */
/*-------------------------------------------------------*/


static int wlen;    /* 本行有多少字 */
static int slen;    /* 本行有多少半形字 */


static void
foutc(ch, fp)
  int ch;
  FILE *fp;
{
  static int in_tag = 0;    /* 1: 在 <tag> 中 */
  static int in_chi = 0;    /* 1: 前一碼是中文字 */

  if (ch == '<')
  {
    in_tag = 1;
    return;
  }

  if (!in_tag)
  {
    if (in_chi || ch & 0x80)    /* 前一個char或這char是中文字的第一碼 */
      in_chi ^= 1;
    else                        /* 如果都不是,表示這char是半形字 */
      slen++;

    if (wlen >= 60 - slen % 2)  /* 一行最多 60 字,若有奇數個半形字,
                                   該行只印 59 字 */
    {
      fputs("\n    ", fp);      /* 每行前面都空四格 */
      wlen = 0;
      /* slen = 0; */
      slen = !in_chi;           /* 若新的這行第一個char是半形字,slen=1 */
    }

    fputc(ch, fp);
    wlen++;
  }
  else
  {
    if (ch == '>')
      in_tag = 0;
  }
}


static void
fouts(str, fp)
  uschar *str;
  FILE *fp;
{
  int ch;

  wlen = 0;
  slen = 0;
  fputs("\n    ", fp);      /* 每行前面都空四格 */

  while (ch = *str)
  {
    foutc(ch, fp);
    str++;
  }
}


static void
html_download(enews, fold)      /* 下載文章並轉換為文字檔 */
  ENEWS *enews;
  char *fold;
{
  char *strS, *strE;
  char buf[2048];   /* 假設文章每段不會超過 2048 字 */
  char fpath[64];
  FILE *fpr, *fpw;
  int article_begin;

  /* 下載文章 */
  sprintf(buf, LYNX_PATH " %s > " NEWS_FILE, enews->link);
  system(buf);

  /* 轉換為文字檔 */
  if (fpr = fopen(NEWS_FILE, "r"))
  {
    sprintf(fpath, "run/kimo/%c/%s", enews->kind, enews->xname);
    if (fpw = fopen(fpath, "w"))
    {
      /* 開頭加上標題 */
      fprintf(fpw, "%s %s (%s) %s %s\n",
        STR_AUTHOR1, STR_SYSOP, SYSOPNICK, STR_POST2, "奇摩新聞");
      fprintf(fpw, "標題: %s\n時間: %s\n", enews->title, Now());

      /* html -> text */
      article_begin = 0;
      while (fgets(buf, sizeof(buf), fpr))
      {
        if (!article_begin)     /* 文章開始 */
        {
          if (strstr(buf, "<!--end 標題寄給朋友列印-->"))
            article_begin = 1;
          continue;
        }

        /* 文章結束 */
        if (strstr(buf, "<div style=\042clear:both;display:none"))
          break;

        if ((strS = strstr(buf, "<big>")) &&
          (strE = strstr(strS + 5, "</big>")))   /* 本文部分 */
        {
          *strE = '\n';
          *(strE + 1) = '\0';
          fouts(strS + 5, fpw);
          continue;
        }

        if ((strS = strstr(buf, "<small>")) &&
          (strE = strstr(strS + 29, "</font>")))   /* 來源部分 */
        {
          *strE = '\n';
          *(strE + 1) = '\0';
          fouts(strS + 29, fpw);
        }
      }

      /* 結尾加上連結 */
      fprintf(fpw, "\n--\nYahoo!奇摩新聞\n%s\n", enews->link);
      fclose(fpw);

      if (!old_link(fold, enews->link))
        post_board(fpath, enews->title, enews->kind);
    }

    fclose(fpr);
    unlink(NEWS_FILE);  /* 清除暫存檔 */
  }
}


static void
html_fetch(fpath, kind) /* 將這檔案中有效的連結找出來 */
  char *fpath;
  char kind;        /* 種類 */
{
  static int chrono = 0;
  FILE *fp;
  char folder[64], fold[64], buf[1024];
  char *str1, *str2, *str3;
  ENEWS enews;
  int article_num;

  if (!(fp = fopen(fpath, "r")))
    return;

  sprintf(folder, "run/kimo/%c/.ENEWS", kind);
  sprintf(fold, "%s.o", folder);
  f_mv(folder, fold);

#if 0
  處理 HTML 格式如下:
  <a href="/040520/44/nwtu.html" class="title">北市兩公車對撞  13名乘客送醫<!-- 20040520 --></a>
#endif

  article_num = 0;

  while (fgets(buf, 1024, fp) && article_num <= 16)
  {
    if ((str1 = strstr(buf, "<a href=\"/")) &&      /* 只處理連結 */
      (str2 = strstr(str1 + 10, "\" class=\"title\">")) &&
      (str3 = strstr(str2 + 16, "<!-- ")))
    {
      *str2 = '\0';
      *str3 = '\0';

      /* 加入 record */

      memset(&enews, 0, sizeof(ENEWS));
      enews.chrono = ++chrono;      /* 每篇文章一個編號 */
      enews.kind = kind;
      sprintf(enews.xname, "A%06d%c", chrono, kind);
      sprintf(enews.link, YAHOO_URL "%s", str1 + 10);
      str_ncpy(enews.title, str2 + 16, sizeof(enews.title));
      if (!rec_add(folder, &enews, sizeof(ENEWS)))
        html_download(&enews, fold);

      article_num++;
    }
  }

  fclose(fp);
}


/*-------------------------------------------------------*/
/* 主程式                                                */
/*-------------------------------------------------------*/


int
main()
{
  char kind;
  char cmd[256];

  char *class[12] =
  {
    "polity", "society", "international", "twoshore",
    "finance", "entertain", "sports", "leisure",
    "relaxation", "health", "technology", "odd"
  };

  chdir(BBSHOME);

  init_bshm();

  /* 抓 Yahoo cookie */
  system(LYNX_PATH " -dump http://tw.yahoo.com/ > " INDEX_FILE);
  unlink(INDEX_FILE);

  /* 抓資料並分析之 */

  for (kind = 'A'; kind <= 'L'; kind++)
  {
    sprintf(cmd, LYNX_PATH " " YAHOO_URL "%s > " INDEX_FILE,
      class[kind - 'A']);
    system(cmd);
    html_fetch(INDEX_FILE, kind);
    unlink(INDEX_FILE);     /* 清除暫存檔 */
  }

  return 0;
}

--
  Origin:  Maple-itoc˙動力核心  processor.tfcis.org 
  Author: itoc pc512-2.ee.nctu.edu.tw 發表
精華選讀←離開[主題上]主題下(k)上篇(j)下篇S/a搜尋 G串列 TAB精華 ↑↓捲 Pg/Space翻