使用Python构建自定义新闻源

image
  • 来源 | 愿码(ChainDesk.CN)内容编辑
  • 愿码Slogan | 连接每个程序员的故事
  • 网站 | http://chaindesk.cn
  • 愿码愿景 | 打造全学科IT系统免费课程,助力小白用户、初级工程师0成本免费系统学习、低成本进阶,帮助BAT一线资深工程师成长并利用自身优势创造睡后收入。
  • 官方公众号 | 愿码 | 愿码服务号 | 区块链部落
  • 免费加入愿码全思维工程师社群 | 任一公众号回复“愿码”两个字获取入群二维码

本文阅读时长:12min

要创建自定义新闻Feed模型,我们需要可以训练的数据。这些培训数据将被输入模型,以教它区分我们感兴趣的文章和我们不感兴趣的文章。

在本文中,我们将学习构建自定义新闻语料库并分别注释与兴趣相对应的大量文章。

创建受监督的训练数据集


在我们在新闻文章中创建我们的品味模型之前,我们需要培训数据。这些培训数据将被输入我们的模型,以教它区分我们感兴趣的文章和我们不感兴趣的文章。要构建此语料库,我们需要注释大量符合这些兴趣的文章。对于每篇文章,我们将其标记为“y”或“n”。这将表明该文章是否是我们希望在我们的日常摘要中发送给我们的文章。

为简化此过程,我们将使用Pocket应用程序。Pocket是一个应用程序,允许您保存故事以供稍后阅读。您只需安装浏览器扩展,然后在希望保存故事时单击浏览器工具栏中的Pocket图标。该文章将保存到您的个人存储库中。Pocket的一个重要功能就是它的用途,能够使用您选择的标签保存文章。我们将使用此功能将有趣的文章标记为“y”,将非有趣的文章标记为“n”。

安装Pocket Chrome扩展程序

我们在这里使用谷歌浏览器,但其他浏览器应该类似。对于Chrome,请进入Google App Store并查找“扩展”部分:

img

点击蓝色的添加到Chrome按钮。如果您已有帐户,请登录,如果您还没有帐户,请继续注册(免费)。完成后,您应该会在浏览器的右上角看到Pocket图标。它将显示为灰色,但是一旦有想要保存的文章,您可以单击它。保存文章后,它将变为红色,如下图所示。

右上角可以看到灰色图标。

img

单击图标时,它会变为红色,表示文章已保存。

img

开始保存您遇到的所有文章。用“y”标记有趣的标签,用“n”标记非有趣的标签。这将需要一些工作。你的最终结果只会和训练集一样好,所以你需要为数百篇文章做这件事。如果您在保存文章时忘记标记文章,则可以随时访问该网站http://www.get.pocket.com,在其中标记。

使用Pocket API检索故事

既然您已经将文章保存到Pocket,那么下一步就是检索它们。为此,我们将使用Pocket API。您可以通过https:// ge tpocket.com/developer/apps/new注册一个帐户。单击左上角的“ 创建新应用程序 ”并填写详细信息以获取API密钥。确保单击所有权限,以便添加,更改和检索文章。

img

填写完成并提交后,您将收到您的消费者密钥。您可以在“ 我的应用”下的左上角找到此信息。这将看起来像下面的屏幕,但显然有一个真正的键:

img

设置完成后,您就可以继续下一步,即设置授权。它要求您输入您的使用者密钥和重定向URL。重定向网址可以是任何内容。在这里,我使用了我的Twitter帐户:

import requests

auth_params = {'consumer_key': 'MY_CONSUMER_KEY', 'redirect_uri':

'https://www.twitter.com/acombs'}

tkn = requests.post('https://getpocket.com/v3/oauth/request',

data=auth_params)

tkn.content

您将看到以下输出:

img

输出将包含下一步所需的代码。将以下内容放在浏览器栏中:

https://getpocket.com/auth/authorize?request_token=some_long_code&redir ect_uri = https% 3A // www.twitter.com / acombs

如果您将重定向网址更改为您自己的网址,请确保对其进行网址编码。这有很多资源。一种选择是使用Python库urllib,另一种是使用免费的在线源。

此时,您应该看到授权屏幕。继续并批准它,我们可以继续下一步:

usr_params = {'consumer_key':'my_consumer_key', 'code':

'some_long_code'}

usr = requests.post('https://getpocket.com/v3/oauth/authorize',

data=usr_params)

usr.content

我们将在此处使用以下输出代码继续检索故事:

img

首先,我们检索标记为“n”的故事:

no_params = {'consumer_key':'my_consumer_key', 'access_token':

'some_super_long_code',

'tag': 'n'}

no_result = requests.post('https://getpocket.com/v3/get',

data=no_params)

no_result.text

上面的代码生成以下输出:

img

请注意,我们在标记为“n”的所有文章上都有一个长JSON字符串。这里有几个键,但我们实际上只对URL感兴趣。我们将继续创建一个包含以下所有URL的列表:

no_jf = json.loads(no_result.text)

no_jd = no_jf['list']

no_urls=[]

for i in no_jd.values():

no_urls.append(i.get('resolved_url'))

no_urls

上面的代码生成以下输出:

img

此列表包含我们不感兴趣的故事的所有URL。现在,让我们把它放在一个

DataFrame对象并将其标记为:

import pandas

no_uf = pd.DataFrame(no_urls, columns=['urls'])

no_uf = no_uf.assign(wanted = lambda x: 'n')

no_uf

上面的代码生成以下输出:

img

现在,我们都准备好了不想要的故事。让我们对我们感兴趣的故事做同样的事情:

ye_params = {'consumer_key': 'my_consumer_key', 'access_token':

'some_super_long_token',

'tag': 'y'}

yes_result = requests.post('https://getpocket.com/v3/get',

data=yes_params)

yes_jf = json.loads(yes_result.text)

yes_jd = yes_jf['list']

yes_urls=[]

for i in yes_jd.values():

yes_urls.append(i.get('resolved_url'))

yes_uf = pd.DataFrame(yes_urls, columns=['urls'])

yes_uf = yes_uf.assign(wanted = lambda x: 'y')

yes_uf

上面的代码生成以下输出:

img

现在我们的训练数据都有两种类型的故事,让我们将它们组合成一个DataFrame:

df = pd.concat([yes_uf, no_uf])

df.dropna(inplace=1)

df

上面的代码生成以下输出:

img

现在我们在一个框架中设置了所有URL和相应的标签,我们将继续为每篇文章下载HTML。我们将使用另一个名为embed.ly的免费服务。

使用embed.ly API下载故事主体


我们将使用embed.ly来执行此操作,但您还可以使用许多其他服务。

第一步是注册embed.ly API访问。您可以在https://app.embed.ly/signup上执行此操作。这是一个简单的过程。确认注册后,您将收到一个API密钥..您只需在HTTPrequest中使用此密钥即可。我们现在就这样做:

import urllib

def get_html(x):

qurl = urllib.parse.quote(x)

rhtml = requests.get('https://api.embedly.com/1/extract?url=' +

qurl + '&key=some_api_key')

ctnt = json.loads(rhtml.text).get('content')

return ctnt

df.loc[:,'html'] = df['urls'].map(get_html)

df.dropna(inplace=1)

df

上面的代码生成以下输出:

img

有了它,我们有每个故事的HTML。由于内容嵌入在HTML标记中,并且我们希望将纯文本提供给我们的模型,我们将使用解析器去除标记标记:

from bs4 import BeautifulSoup def get_text(x):

soup = BeautifulSoup(x, 'lxml')

text = soup.get_text()

return text

df.loc[:,'text'] = df['html'].map(get_text)

df

上面的代码生成以下输出:

img

有了这个,我们就准备好了训练。我们现在可以继续讨论如何将文本转换为模型可以使用的内容。

设置每日个人简报

为了设置带有新闻故事的个人电子邮件,我们将再次使用IFTTT。构建应用程序以查找廉价机票,我们将使用Maker Channel发送POST请求。

首先,单击IFTTT主页上的Create a Recipe。然后,搜索Maker
频道:

img

选择此项,然后选择接收Web请求:

img

然后,为请求命名。我正在使用news_event:

img

单击“创建触发器”完成。接下来,单击它以设置电子邮件。搜索Gmail并单击如下图标:

img

点击Gmail后,点击发送电子邮件。从这里,您可以自定义您的电子邮件。

img

输入您的电子邮件地址,主题行,最后在电子邮件正文中包含Value1。我们将通过我们的POST请求传递我们的故事标题并链接到此。单击“创建”以完成此操作。

现在,我们已准备好生成将按计划运行的脚本,自动向我们发送感兴趣的文章。我们将为此创建一个单独的脚本,但我们现有代码中需要做的最后一件事是序列化我们的矢量化器和我们的模型:

import pickle pickle.dump(model, open (r'/Users/alexcombs/Downloads/news_model_pickle.p', 'wb')) pickle.dump(vect, open (r'/Users/alexcombs/Downloads/news_vect_pickle.p', 'wb'))

有了这个,我们从模型中保存了所需的一切。在我们的新脚本中,我们将阅读这些内容以生成新的预测。我们将使用相同的调度库来运行我们在第3章“构建应用程序以查找廉价机票”中使用的代码。总而言之,我们有以下脚本:

# get our imports. import pandas as pd

from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.svm import LinearSVC

import schedule import time
import pickle import json import gspread import requests
from bs4 import BeautifulSoup

from oauth2client.client import SignedJwtAssertionCredentials


# create our fetching function def fetch_news():
try:
vect =
pickle.load(open(r'/Users/alexcombs/Downloads/news_vect_pickle.p', 'rb'))
model =
pickle.load(open(r'/Users/alexcombs/Downloads/news_model_pickle.p', 'rb'))

json_key =
json.load(open(r'/Users/alexcombs/Downloads/APIKEY.json'))
scope = ['https://spreadsheets.google.com/feeds']


credentials = SignedJwtAssertionCredentials(json_key['client_email'], json_key['private_key'].encode(), scope)
gc = gspread.authorize(credentials)

ws = gc.open("NewStories")
sh = ws.sheet1
zd = list(zip(sh.col_values(2), sh.col_values(3),
sh.col_values(4)))
zf = pd.DataFrame(zd, columns=['title', 'urls', 'html'])
zf.replace('', pd.np.nan, inplace=True)
zf.dropna(inplace=True)

def get_text(x):
soup = BeautifulSoup(x, 'lxml')
text = soup.get_text()
return text

zf.loc[:, 'text'] = zf['html'].map(get_text)

tv = vect.transform(zf['text'])
res = model.predict(tv)

rf = pd.DataFrame(res, columns=['wanted'])
rez = pd.merge(rf, zf, left_index=True, right_index=True)

news_str = ''
for t, u in zip(rez[rez['wanted'] == 'y']['title'],
rez[rez['wanted'] == 'y']['urls']):
news_str = news_str + t + '\n' + u + '\n'

payload = {"value1": news_str}
r =
requests.post('https://maker.ifttt.com/trigger/news_event/with/key/IFTTT_KE
Y', data=payload)

# cleanup worksheet
lenv = len(sh.col_values(1))
cell_list = sh.range('A1:F' + str(lenv))
for cell in cell_list:
cell.value = ""
sh.update_cells(cell_list)
print(r.text)
except:
print('Failed')

schedule.every(480).minutes.do(fetch_news)


while 1: schedule.run_pending() time.sleep(1)

这个脚本将每隔4小时运行一次,从Google表格下载新闻报道,通过模型运行故事,通过向IFTTT发送POST请求以生成预期感兴趣的故事,生成电子邮件,最后,它将清除电子表格中的故事,以便在下一封电子邮件中只发送新故事。

恭喜!您现在拥有自己的个性化新闻Feed!

你可能感兴趣的:(使用Python构建自定义新闻源)