往往在遇到困難的時候,換個思考方向即可找到更好的解決方案,因此不要埋頭苦幹完成任務,畢竟自己沒有好的編程能力,沒有必要硬是使用目前僅有的技術而顯得黔驢技窮。
當網站擷取變得越來越困難,專業化的應用服務也會越來越興盛,尤其是新聞擷取這種常見的資訊需求,一定也有API等整理好的資源可以使用,因此我找到了News API,可以完美地幫我們完成收集新聞的任務。News API本身也是透過網站擷取來收集新聞,目前已收集超過30000個出處、54個國家,我們可以查看新聞出處,了解News API已將所有新聞爬得又深又廣,亦不會胡亂擷取內容真實性有疑慮的八卦小報新聞。
News API也有擷取中華民國(台灣)的新聞。
以下內容分為「關於News API」、「儲存至news.csv」、「儲存至news.xlsx」、「修改news.xlsx並儲存至selectedNews.xlsx」共四個部分,其中修改news.xlsx的部分是依照公司系統欄位需求所做的調整,試想當其他同事還在辛苦地一筆一筆查找新聞資料時,我們已經又快又好地完成任務,是多麼有成就感呀!
收集並更新新聞的工作如果每天都必須執行,我們甚至可以寫支程式,讓資料直接存入資料庫,透過每日一次的排程讓電腦自動執行,往後公司網頁系統平台上顯示的主題新聞,都不再需要透過人工作業來維護,讓人力可以專注在其它重要的任務上,這聽起來不是很棒嗎?
一、關於News API
News API基本介紹
l Homepage: News API
l Subscription Plan: Developer
Free for Open Source Project, Non-commercial Project, and Commercial Project in Development
開發者權限完全免費,但是有使用限制,以避免資源被隨意耗用:
每6個小時可以向News API請求250次,每24個小時可以向News API請求1000次。
News API每次預設回傳20則新聞,最多每次指定回傳100則新聞,換句話說,每6個小時最多可以擷取25000則新聞,以關鍵字搜尋新聞而言,約為累積10個月以上的新聞則數,以免費的權限來說,已經非常好用了。
Free for Open Source Project, Non-commercial Project, and Commercial Project in Development
開發者權限完全免費,但是有使用限制,以避免資源被隨意耗用:
每6個小時可以向News API請求250次,每24個小時可以向News API請求1000次。
News API每次預設回傳20則新聞,最多每次指定回傳100則新聞,換句話說,每6個小時最多可以擷取25000則新聞,以關鍵字搜尋新聞而言,約為累積10個月以上的新聞則數,以免費的權限來說,已經非常好用了。
l Documentation:
News API回傳JSON格式的資料,請求資料時可以傳送的變數,以及收到資料的結構,網站文件皆有清楚說明。
News API目前提供頭條搜尋(Top Headlines)、關鍵字搜尋(Everything),以及類別搜尋(Sources)共3種搜尋方法。
News API回傳JSON格式的資料,請求資料時可以傳送的變數,以及收到資料的結構,網站文件皆有清楚說明。
News API目前提供頭條搜尋(Top Headlines)、關鍵字搜尋(Everything),以及類別搜尋(Sources)共3種搜尋方法。
l Register for API Key:
註冊並取得API Key之後,便可以傳送網址,收到JSON資料,例如:
https://newsapi.org/v2/everything?q="巨量資料"OR"大數據"&from=2018-06-21&to=2018-06-21&language=zh&page=1&apiKey=API_KEY
註冊並取得API Key之後,便可以傳送網址,收到JSON資料,例如:
https://newsapi.org/v2/everything?q="巨量資料"OR"大數據"&from=2018-06-21&to=2018-06-21&language=zh&page=1&apiKey=API_KEY
News API Python Client Library
l News API可以透過多種程式語言進行操作,亦提供各種程式語言套件,然而以Python操作來說,使用套件並沒有比較方便,反而還可能要修改Library的語法,例如中文代碼'zh'沒有被加入套件的const.py檔案,必須自己補上,詳細資訊可參考News API Python Client Library的GitHub。
l 在命令提示字元輸入pip install newsapi-python,下載並安裝News API Python Client Library。
l from newsapi import NewsApiClient
API_KEY = input('Your API key is: ')
newsapi = NewsApiClient(api_key=API_KEY)
all_articles = newsapi.get_everything(q='"巨量資料"OR"大數據"', from_param='2018-06-21', to='2018-06-21', language='zh', page=1)
print(all_articles)
API_KEY = input('Your API key is: ')
newsapi = NewsApiClient(api_key=API_KEY)
all_articles = newsapi.get_everything(q='"巨量資料"OR"大數據"', from_param='2018-06-21', to='2018-06-21', language='zh', page=1)
print(all_articles)
二、儲存至news.csv
import requests, json, csv
API_KEY = input('Your API key is: ')
pageNum = 1
totalPageNum = 1
newsFile = open('D:\\news.csv', 'w', newline = '', encoding = 'utf-8-sig')
newsWriter = csv.writer(newsFile)
newsWriter.writerow(['id', 'name', 'author', 'title', 'description', 'url', 'urlToImage', 'publishedAt'])
newsFile.close()
def newsAPIPages():
newsFile = open('D:\\news.csv', 'a', newline = '', encoding = 'utf-8-sig')
newsWriter = csv.writer(newsFile)
url = ('https://newsapi.org/v2/everything?'
'q="巨量資料"OR"大數據"&'
'from=2018-06-21&'
'to=2018-06-21&'
'language=zh&'
'page=' + str(pageNum) + '&'
'apiKey=' + API_KEY)
aRes = requests.get(url)
newsDict = json.loads(aRes.text)
print('status: ' + newsDict['status'])
print('totalResults: ' + str(newsDict['totalResults']))
global totalPageNum
totalPageNum = int(newsDict['totalResults']/20) + 1
print('Retrieving Page ' + str(pageNum) + '/' + str(totalPageNum))
for article in newsDict['articles']:
newsWriter.writerow([article['source']['id'], \
article['source']['name'], \
article['author'], \
article['title'], \
article['description'], \
article['url'], \
article['urlToImage'], \
article['publishedAt']])
newsFile.close()
newsAPIPages()
while pageNum < totalPageNum:
pageNum += 1
newsAPIPages()
三、儲存至news.xlsx
import requests, json, openpyxl
from openpyxl.utils import get_column_letter, column_index_from_string
API_KEY = input('Your API key is: ')
pageNum = 1
totalPageNum = 1
columnNum = 1
rowNum = 2
newsBook = openpyxl.Workbook()
newsSheet = newsBook.active
newsSheet.title = 'news'
header = ['id', 'name', 'author', 'title', 'description', 'url', 'urlToImage', 'publishedAt']
for item in header:
newsSheet[get_column_letter(columnNum) + '1'] = item
columnNum += 1
newsBook.save('D:\\news.xlsx')
def newsAPIPages():
newsBook = openpyxl.load_workbook('D:\\news.xlsx')
newsSheet = newsBook.active
url = ('https://newsapi.org/v2/everything?'
'q="巨量資料"OR"大數據"&'
'from=2018-06-21&'
'to=2018-06-21&'
'language=zh&'
'page=' + str(pageNum) + '&'
'apiKey=' + API_KEY)
aRes = requests.get(url)
newsDict = json.loads(aRes.text)
print('status: ' + newsDict['status'])
print('totalResults: ' + str(newsDict['totalResults']))
global totalPageNum
totalPageNum = int(newsDict['totalResults']/20) + 1
print('Retrieving Page ' + str(pageNum) + '/' + str(totalPageNum))
global columnNum
global rowNum
for article in newsDict['articles']:
articleList = []
articleList.append(article['source']['id'])
articleList.append(article['source']['name'])
articleList.append(article['author'])
articleList.append(article['title'])
articleList.append(article['description'])
articleList.append(article['url'])
articleList.append(article['urlToImage'])
articleList.append(article['publishedAt'])
columnNum = 1
for item in articleList:
newsSheet[get_column_letter(columnNum) + str(rowNum)] = item
columnNum += 1
rowNum += 1
newsBook.save('D:\\news.xlsx')
newsAPIPages()
while pageNum < totalPageNum:
pageNum += 1
newsAPIPages()
四、修改news.xlsx並儲存至selectedNews.xlsx
# 修改目標一:挑選並排序欄位
# 修改目標二:只挑出連結名稱(title)有關鍵字的新聞
# 修改目標三:排除相同連結名稱(title)的新聞
# 修改目標四:變更日期(publishedAt)格式
import openpyxl, re
from openpyxl.utils import get_column_letter, column_index_from_string
newsBook = openpyxl.load_workbook('D:\\news.xlsx')
newsSheet = newsBook.active
selectedNewsBook = openpyxl.Workbook()
selectedNewsSheet = selectedNewsBook.active
selectedNewsSheet.title = 'selectedNews'
header = ['連結名稱(title)', '出處(name)', '日期(publishedAt)', '連結網址(url)']
selectedColumnNum = 1
for item in header:
selectedNewsSheet[get_column_letter(selectedColumnNum) + '1'] = item
selectedColumnNum += 1
titleList = []
selectedRowNum = 2
for row in range(2, newsSheet.max_row + 1):
bufferedList = []
# title
originalTitle = str(newsSheet['D' + str(row)].value)
aRegex = re.compile(r'巨量資料|大數據')
if aRegex.search(originalTitle) == None:
continue
if originalTitle in titleList:
continue
titleList.append(originalTitle)
bufferedList.append(originalTitle)
# name
bufferedList.append(newsSheet['B' + str(row)].value)
# publishedAt
originalFormat = newsSheet['H' + str(row)].value
bRegex = re.compile(r'\d\d\d\d-\d\d-\d\d')
bufferedFormat = str(bRegex.search(originalFormat).group())
newFormat = bufferedFormat.replace('-', '/')
bufferedList.append(newFormat)
# url
bufferedList.append(newsSheet['F' + str(row)].value)
selectedColumnNum = 1
for item in bufferedList:
selectedNewsSheet[get_column_letter(selectedColumnNum) + str(selectedRowNum)] = item
selectedColumnNum += 1
selectedRowNum += 1
selectedNewsBook.save('D:\\selectedNews.xlsx')
newsBook.close()
作者已經移除這則留言。
回覆刪除請教一下,您在文章一開始提到「工作上被指派…」,但這似乎和 News API 提供的 "免費" 條件 (禁止商用) 衝突 (https://newsapi.org/pricing)。請教您是否有別的法務解釋或是處理辦法可以參考呢?
回覆刪除很好的問題:
刪除1. 新聞資料本身不是需要付費與否的因素,而是使用API這項服務來達成自己的獲益目的,這才存在商用與否的疑慮。以我在前份工作使用這個API服務的目的來說,僅為取得新聞資料而已,且新聞資料整理後所放置的網頁系統平台,完全沒有商業行為(是政府單位的服務,所以一個廣告都沒有),因此沒有商用的疑慮。
2. 對API服務提供者來說,大量的資料請求需求是耗用資源的關鍵,所以Developer免費的權限限制很多(在我寫這篇網誌的時候,免費的權限還不像現在有那麼大的限制),所以即便多數使用情境下,不容易違反"禁止商用"條款,也會因為不敷使用而得升級為Business或Enterprise付費的權限。
3. 若真的有使用此API服務來達成自己的商業行為,只要是原型階段的商業行為,仍被接受的(For all non-commercial projects and in-development commercial projects.),如果是具規模、成熟的商業行為,還是建議付費使用(其實在此階段之前,免費的權限應該早就不夠用了)。