Skip to content

Commit d27693f

Browse files
committed
Improved readability and removed unnecessary functionality
1 parent 292abaf commit d27693f

File tree

6 files changed

+80
-83
lines changed

6 files changed

+80
-83
lines changed

.idea/inspectionProfiles/Project_Default.xml

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

finviz/request_functions.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88

99
def http_request(url, payload=None):
1010

11+
""" Makes http request to a URL address """
12+
1113
if payload is None:
1214
payload = {}
1315

1416
content = requests.get(url, params=payload, verify=False)
1517
content.raise_for_status() # Raise HTTPError for bad requests (4xx or 5xx)
1618

17-
return content, content.url
19+
return content.text, content.url
1820

1921

2022
class Connector(object):
@@ -27,13 +29,17 @@ def __init__(self, scrape_function, tasks):
2729

2830
async def __http_request__async(self, url, session):
2931

32+
""" Sends asynchronous http request to URL address and scrapes the webpage. """
33+
3034
async with session.get(url) as response:
3135
page_html = await response.read()
3236

3337
return self.scrape_function(page_html, url)
3438

3539
async def __async_scraper(self):
3640

41+
""" Appends URL's into tasks and gathers their output. """
42+
3743
async_tasks = []
3844
async with aiohttp.ClientSession() as session:
3945
for n in self.tasks:

finviz/save_data.py

+1-13
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def create_connection():
1616

1717
def export_to_csv(headers, data):
1818

19-
with open('/screener_results.csv', 'w', newline='') as output_file:
19+
with open('screener_results.csv', 'w', newline='') as output_file:
2020
dict_writer = csv.DictWriter(output_file, headers)
2121
dict_writer.writeheader()
2222

@@ -61,15 +61,3 @@ def export_to_db(headers, data):
6161

6262
conn.commit()
6363
conn.close()
64-
65-
66-
def select_from_db():
67-
68-
conn = create_connection()
69-
c = conn.cursor()
70-
c.execute("SELECT * FROM screener_results")
71-
72-
rows = c.fetchall()
73-
74-
for row in rows:
75-
print(row)

finviz/scraper_functions.py

+7
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,20 @@
33

44

55
def get_total_rows(page_content):
6+
7+
"""
8+
Gets the total rows of the table. This function is called when the user does not provide a number of rows that have to be scraped.
9+
"""
10+
611
total_element = page_content.cssselect('td[width="140"]')
712

813
return int(etree.tostring(total_element[0]).decode("utf-8").split('</b>')[1].split(' ')[0])
914

1015

1116
def get_page_urls(page_content, rows, url):
1217

18+
""" Gets the page URL addresses """
19+
1320
try:
1421
total_pages = int([i.text.split('/')[1] for i in page_content.cssselect('option[value="1"]')][0])
1522
except IndexError:

finviz/screener.py

+49-63
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from .save_data import export_to_db, select_from_db, export_to_csv
1+
from finviz.request_functions import Connector, http_request
2+
from .save_data import export_to_db, export_to_csv
23
from urllib.parse import urlencode
34
from lxml import html
45
from lxml import etree
5-
import finviz.request_functions as send
66
import finviz.scraper_functions as scrape
77

88

@@ -11,45 +11,53 @@ class Screener(object):
1111
def __init__(self, tickers=None, filters=None, rows=None, order='', signal='', table='Overview'):
1212

1313
if tickers is None:
14-
self.tickers = []
14+
self._tickers = []
1515
else:
16-
self.tickers = tickers
16+
self._tickers = tickers
1717

1818
if filters is None:
19-
self.filters = []
19+
self._filters = []
2020
else:
21-
self.filters = filters
22-
23-
self.rows = rows
24-
self.order = order
25-
self.signal = signal
26-
self.table = table
27-
self.page_content = None
28-
self.url = None
29-
self.headers = None
30-
self.page_urls = None
31-
self.data = None
21+
self._filters = filters
3222

33-
self.__search_screener()
23+
self._table_types = {
24+
'Overview': '110',
25+
'Valuation': '120',
26+
'Ownership': '130',
27+
'Performance': '140',
28+
'Custom': '150',
29+
'Financial': '160',
30+
'Technical': '170'
31+
}
3432

35-
def to_sqlite(self):
33+
self._page_unparsed, self._url = http_request('https://finviz.com/screener.ashx', payload={
34+
'v': self._table_types[table],
35+
't': ','.join(self._tickers),
36+
'f': ','.join(self._filters),
37+
'o': order,
38+
's': signal
39+
})
3640

37-
export_to_db(self.headers, self.data)
41+
self._page_content = html.fromstring(self._page_unparsed)
42+
self._headers = self.__get_table_headers()
3843

39-
def display_db(self):
44+
if rows is None:
45+
self._rows = scrape.get_total_rows(self._page_content)
46+
else:
47+
self._rows = rows
4048

41-
select_from_db()
49+
self.data = None
50+
self.__search_screener()
4251

43-
def to_csv(self):
52+
def to_sqlite(self):
53+
export_to_db(self._headers, self.data)
4454

45-
export_to_csv(self.headers, self.data)
55+
def to_csv(self):
56+
export_to_csv(self._headers, self.data)
4657

47-
def get_charts(self, period='d', size='l', chart_type='c', ta=None, save_to=None):
58+
def get_charts(self, period='d', size='l', chart_type='c', ta='1'):
4859

49-
if ta is True or None: # Charts include TA by default
50-
ta = '1'
51-
else:
52-
ta = '0'
60+
""" Asynchronously downloads charts of tickers displayed by the screener. """
5361

5462
payload = {
5563
'ty': chart_type,
@@ -65,13 +73,14 @@ def get_charts(self, period='d', size='l', chart_type='c', ta=None, save_to=None
6573
for row in page:
6674
chart_urls.append(base_url + '&t={}'.format(row.get('Ticker')))
6775

68-
async_connector = send.Connector(scrape.download_image, chart_urls)
69-
async_connector.directory = save_to
76+
async_connector = Connector(scrape.download_image, chart_urls)
7077
async_connector.run_connector()
7178

7279
def __get_table_headers(self):
7380

74-
first_row = self.page_content.cssselect('tr[valign="middle"]')
81+
""" Scrapes the table headers from the initial page. """
82+
83+
first_row = self._page_content.cssselect('tr[valign="middle"]')
7584

7685
headers = []
7786
for table_content in first_row[0]:
@@ -82,10 +91,12 @@ def __get_table_headers(self):
8291
else:
8392
headers.append(table_content.text)
8493

85-
self.headers = headers
94+
return headers
8695

8796
def __get_table_data(self, page=None, url=None):
8897

98+
""" Returns the data, from each row of the table, inside a dictionary ."""
99+
89100
def parse_row(line):
90101

91102
row_data = []
@@ -104,46 +115,21 @@ def parse_row(line):
104115

105116
for row in all_rows:
106117

107-
if int(row[0].text) is self.rows:
108-
values = dict(zip(self.headers, parse_row(row)))
118+
if int(row[0].text) is self._rows:
119+
values = dict(zip(self._headers, parse_row(row)))
109120
data_sets.append(values)
110121
break
111122

112123
else:
113-
values = dict(zip(self.headers, parse_row(row)))
124+
values = dict(zip(self._headers, parse_row(row)))
114125
data_sets.append(values)
115126

116127
return data_sets
117128

118129
def __search_screener(self):
119130

120-
table = {
121-
'Overview': '110',
122-
'Valuation': '120',
123-
'Ownership': '130',
124-
'Performance': '140',
125-
'Custom': '150',
126-
'Financial': '160',
127-
'Technical': '170'
128-
}
129-
130-
payload = {
131-
'v': table[self.table],
132-
't': ','.join(self.tickers),
133-
'f': ','.join(self.filters),
134-
'o': self.order,
135-
's': self.signal
136-
}
137-
138-
self.page_content, self.url = send.http_request('https://finviz.com/screener.ashx', payload)
139-
self.page_content = html.fromstring(self.page_content.text) # Parses the page with the default lxml parser
140-
141-
self.__get_table_headers()
142-
143-
if self.rows is None:
144-
self.rows = scrape.get_total_rows(self.page_content)
145-
146-
self.page_urls = scrape.get_page_urls(self.page_content, self.rows, self.url)
131+
""" Saves data from the FinViz screener. """
147132

148-
async_connector = send.Connector(self.__get_table_data, self.page_urls)
133+
page_urls = scrape.get_page_urls(self._page_content, self._rows, self._url)
134+
async_connector = Connector(self.__get_table_data, page_urls)
149135
self.data = async_connector.run_connector()

setup.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
setup(
33
name = 'finviz',
44
packages = ['finviz'],
5-
version = '1.1',
5+
version = '1.1.1',
66
license='MIT',
77
description = 'Unofficial API for finviz.com',
88
author = 'Mario Stoev',
9-
author_email = '[email protected]', # Type in your E-Mail
10-
url = 'https://github.com/mariostoev/finviz', # Provide either the link to your github or to your website
11-
download_url = 'https://github.com/user/reponame/archive/v_01.tar.gz', # I explain this later on
12-
keywords = ['finviz', 'api', 'screener', 'finviz api', 'charts', 'scraper'], # Keywords that define your package best
13-
install_requires=[ # I get to this in a second
9+
author_email = '[email protected]',
10+
url = 'https://github.com/mariostoev/finviz',
11+
download_url = 'https://github.com/user/reponame/archive/v_01.tar.gz',
12+
keywords = ['finviz', 'api', 'screener', 'finviz api', 'charts', 'scraper'],
13+
install_requires=[
1414
'lxml',
1515
'requests',
1616
'aiohttp',

0 commit comments

Comments
 (0)