Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

# C extensions
*.so

# Distribution / packaging
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
.tox/
.coverage
.cache
nosetests.xml
coverage.xml

# Translations
*.mo

# Mr Developer
.mr.developer.cfg
.project
.pydevproject

# Rope
.ropeproject

# Django stuff:
*.log
*.pot

# Sphinx documentation
docs/_build/

Test_file.json
Empty file added __init__.py
Empty file.
113 changes: 110 additions & 3 deletions final_task/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,110 @@
# Your readme here
Some text.
Checkout how to write this file using *markdown*.
#The best RSS-reader!
Program is named rss_reader.py.
##Instalation
The recommended way to install rss-reader is with pip:
* pip install rss_reader-5.0.tar.gz - for Windows
* sudo pip install rss_reader-5.0.tar.gz - for Linux and Mac

##Description and Functions
```
usage: rss_reader.py [-h] [--limit LIMIT] [--version] [--json] [--verbose]
[--date DATE] [--to_pdf TO_PDF] [--to_epub TO_EPUB]
[--colorize]
[source]

Pure Python command-line RSS reader.

positional arguments:
source RSS URL

optional arguments:
-h, --help show this help message and exit
--limit LIMIT Limit news topics if this parameter provided
--version Print version info
--json Print result as JSON in stdout
--verbose Outputs verbose status messages
--date DATE Return news from cache with that date
--to_pdf TO_PDF Conversion of news in the pdf format
--to_epub TO_EPUB Conversion of news in the epub format
--colorize Print news in colorized mode in stdout
```

To run the program from the command line, you must write the file name and string with URL-address of news site.

It's print a brief description of the news information that appeared on the news site in human-readable
format and save them in cache.

Example:
```python rss_reader.py "https://news.yahoo.com/rss/" --limit 1

Feed: Yahoo News - Latest News & Headlines

Updated: Sun, 24 Nov 2019 21:19:04 GMT

Version: rss20
--------------------------------------------------------
Title: Ukraine's President Zelensky said he didn't feel pressured by Trump. Here
's why that's bogus.
Date: Sat, 23 Nov 2019 08:57:00 -0500
Link: https://news.yahoo.com/ukraines-president-zelensky-said-didnt-135700678.ht
ml
Summary: [Image: Ukraine's President Zelensky said he didn't feel pressured by
Trump. Here's why that's bogus.] The US government's assistance to Ukraine is vi
tal as it contends with an ongoing conflict with pro-Russian separatists in the
Donbas region.
Source of image: http://l2.yimg.com/uu/api/res/1.2/3h5JxcDjAP1pHR6KUD2JMQ--/YXBw
aWQ9eXRhY2h5b247aD04Njt3PTEzMDs-/https://media.zenfs.com/en-US/business_insider_
articles_888/7a21ff2ee09c3b4285094c4e64e9602c
```
###Nice features
To please the eyes you can read news from console in a colorful format.
For this enter such parameter like --colorize and enjoy.

But this parameter work only for MAC and Linux console.

###How to read saving news:
If you want to read saved news of a certain date, you must enter a --date in %Y%m%d format and the program will work
without any connecting to the Internet.

It is also possible to select news from a specific source of a certain date, for this you must enter the url-address
and --date that you want.

###What formats can you convert to? How to do it.
Program can convert news in ```--to_pdf``` and ```--to_epub``` format.
Specify the path to the file yourself. Also program convert news in ```--json``` format
but print result as JSON in stdout.

JSON format example:
```json
[
{
"Feed": "Yahoo",
"Updated": "Fri, 08 Nov 2019 17:04:06 GMT",
"Version": "rss20"
},
{
"Title": "Some title",
"Date": "Thu, 07 Nov 2019 09:59:52 -0500",
"Summary": "Some summary",
"Link": "Link to news",
"Image": "Some image information"
}
]
```
#####Ways for converting:
- *You can convert from cache*

For this case news conversion is not depend on internet.
With ```rss_reader.py --date 20191117 --limit 1 --to_pdf /folder1/folder2/file_name.pdf``` one news for the specified day
would be converted (the same with ```--to_epub```) and would be generated or overwritten file 'file_name.pdf'
in folder what you choose.

- *You can convert news from the Internet*

For this case Internet is required.
With ```rss_reader.py https://news.yahoo.com/rss/ --limit 1 --to_pdf /folder1/folder2/file_name.pdf``` one news
from specified link would be converted (the same with ```--to_epub```)and would be generated or overwritten
file 'file_name.epub' in folder what you choose.



49 changes: 49 additions & 0 deletions final_task/rss_reader/NewsCache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import json
import os.path
import logging


class NewsCache:
"""Class which create json-file with cached news,
saved all fresh news and return them with certain date
and from certain url-address if such url will be introduced."""

def __init__(self, file_name):
self.logger = logging.getLogger(__name__)
self.file_name = file_name
self.logger.info("Check for cache file...")
if os.path.isfile(file_name):
try:
with open(file_name, "r") as json_file:
self.cache_news = json.load(json_file)
self.logger.info("Reading cache file...")
except Exception as ex:
self.logger.error("Error reading file: {} {}".format(type(ex), ex))
Comment thread
HenadziStantchik marked this conversation as resolved.
self.cache_news = {}
else:
self.logger.warning("Warning! Caching file is not found!")
self.cache_news = {}

def caching(self, all_news, url):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and below: please use more informative method names

"""Function which create JSON-file
and save news."""
for dictionary in all_news:
date_in_news = dictionary.pop('Date key')
title = dictionary['Title']
self.cache_news.setdefault(date_in_news, {}).setdefault(url, {}).setdefault(title, dictionary)
with open(self.file_name, "w") as file_to_write:
self.logger.info("News caching...")
file_to_write.write(json.dumps(self.cache_news))

def returning(self, desired_date, desired_url=None):
"""Function which return news from cache-file with certain date
and from certain url-address if such url will be introduced."""
self.logger.info('News search in cache...')
caching_news_list = []
if desired_url is not None:
caching_news_list = list(self.cache_news.get(desired_date, {}).get(desired_url, {}).values())
else:
answer = self.cache_news.get(desired_date, {})
for title in answer.values():
caching_news_list += title.values()
return caching_news_list
126 changes: 126 additions & 0 deletions final_task/rss_reader/RSSReader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import datetime
import feedparser
import logging
from bs4 import BeautifulSoup
from RSSReaderException import RSSReaderException
from NewsCache import NewsCache
from unidecode import unidecode
from output import get_output_function

CACHE_FILE_NAME = "Cache file.json"


class RSSReader:

def __init__(self, date, url, limit, is_json, pdf_file_name, epub_file_name, color):
self.cache = NewsCache(CACHE_FILE_NAME)
self.date = date
self.url = url
self.is_json = is_json
self.limit = limit
self.pdf_file_name = pdf_file_name
self.epub_file_name = epub_file_name
self.color = color
self.logger = logging.getLogger(__name__)

def url_parsing(self):
parsed_url = feedparser.parse(self.url)
if parsed_url.status != 200: # URL-access check
self.logger.error("Can't load RSS feed.")
raise RSSReaderException('RSS-reader failed. Status: {}.'.format(parsed_url.status))
else:
self.logger.info('RSS parsed successfully!')
return parsed_url

def information_about_site(self, parsed_url):
"""Function which make dictionary with data of website"""
date = parsed_url.get('updated', str(datetime.datetime.now()))
return {
'Feed': unidecode(parsed_url['feed']['title']),
'Updated': date,
'Version': unidecode(parsed_url['version']),
}

def make_news_data(self, news):
"""
Function which parsed HTML summary of news and make dictionary with all the necessary news data.
:return dictionary
"""
image_link = 'No image'
if 'summary' in news:
# convert_to_epub(news['summary'])
bs = BeautifulSoup(news['summary'], 'html.parser')
img = bs.find_all('img')
if img:
image_description = unidecode(img[0].get('alt', 'no description'))
image_link = img[0].get('src')
img[0].replaceWith(f' [Image: {image_description}] ')
summary = unidecode(str(bs.text))
else:
summary = news['title']
date_info = news['published_parsed'] if 'published' in news else news['updated_parsed']
date_key = str("{}{}{}".format(date_info.tm_year, date_info.tm_mon, date_info.tm_mday))
news_summary = {
'Title': unidecode(news['title']),
'Date': news['published'] if 'published' in news else news['updated'],
'Link': news['link'],
'Summary': summary,
'Source of image': image_link,
'Date key': date_key
}
return news_summary

def news_data_collection(self, parsed_url):
"""Function that collects data from all news by calling make_news_data.
:return string of dictionaries
"""
all_information_about_news = parsed_url['entries']
# amount_of_news = len(parsed_url.entries)
all_news = []
self.logger.info('News gathering')
for news in all_information_about_news[:self.limit]:
try: # Exception when news is failed
dictionary_of_news_data = self.make_news_data(news)
except Exception as ex:
self.logger.error("Error processing news: {} {}".format(type(ex), ex))
else:
all_news.append(dictionary_of_news_data) # make list of dictionaries of news data for optional output
return all_news

def get_news(self):
"""Get news!"""
if self.date is None:
if self.url is None:
self.logger.error("URL is not provided.")
return
self.logger.info('Start parsing...')
try:
parsed_url = self.url_parsing()
about_website = self.information_about_site(parsed_url)
except Exception as ex: # for any exception after website parsing
self.logger.error("Error reading site data: {}, {}.".format(type(ex), ex))
return
string_of_news_dictionaries = self.news_data_collection(parsed_url)
self.cache.caching(string_of_news_dictionaries, self.url)
else:
string_of_news_dictionaries = self.cache.returning(self.date, self.url)[:self.limit]
about_website = None
if not string_of_news_dictionaries:
self.logger.error('There is no news.')
return
file_name = None
if self.is_json:
converter = 'json'
elif self.pdf_file_name:
converter = 'pdf'
file_name = self.pdf_file_name
elif self.epub_file_name:
converter = 'epub'
file_name = self.epub_file_name
elif self.color:
converter = 'color'
else:
self.logger.info('Output news')
converter = 'text'
output = get_output_function(converter)
output(self.logger, string_of_news_dictionaries, about_website, file_name)
2 changes: 2 additions & 0 deletions final_task/rss_reader/RSSReaderException.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class RSSReaderException(Exception):
pass
Empty file.
Loading