Skip to content

Commit a60021a

Browse files
committed
Fixed IndexError: list index out of range after NSE updated the method they use for loading stocks, this also means that web scraping is no longer required
1 parent c1089d1 commit a60021a

File tree

1 file changed

+13
-39
lines changed

1 file changed

+13
-39
lines changed

NSE_Option_Chain_Analyzer.py

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from tkinter.ttk import Combobox, Button
1212
from typing import Union, Optional, List, Dict, Tuple, TextIO, Any
1313

14-
import bs4
1514
import pandas
1615
import requests
1716
import streamtologger
@@ -43,8 +42,7 @@ def __init__(self, window: Tk) -> None:
4342
self.url_oc: str = "https://www.nseindia.com/option-chain"
4443
self.url_index: str = "https://www.nseindia.com/api/option-chain-indices?symbol="
4544
self.url_stock: str = "https://www.nseindia.com/api/option-chain-equities?symbol="
46-
self.url_symbols: str = "https://www.nseindia.com/products-services/" \
47-
"equity-derivatives-list-underlyings-information"
45+
self.url_symbols: str = "https://www.nseindia.com/api/underlying-information"
4846
self.url_icon_png: str = "https://raw.githubusercontent.com/VarunS2002/" \
4947
"Python-NSE-Option-Chain-Analyzer/master/nse_logo.png"
5048
self.url_icon_ico: str = "https://raw.githubusercontent.com/VarunS2002/" \
@@ -56,6 +54,8 @@ def __init__(self, window: Tk) -> None:
5654
'like Gecko) Chrome/80.0.3987.149 Safari/537.36',
5755
'accept-language': 'en,gu;q=0.9,hi;q=0.8',
5856
'accept-encoding': 'gzip, deflate, br'}
57+
self.session: requests.Session = requests.Session()
58+
self.cookies: Dict[str, str] = {}
5959
self.get_symbols(window)
6060
self.config_parser: configparser.ConfigParser = configparser.ConfigParser()
6161
self.create_config(new=True) if not os.path.isfile('NSE-OCA.ini') else None
@@ -70,8 +70,6 @@ def __init__(self, window: Tk) -> None:
7070
'Time', 'Value', f'Call Sum ({self.units_str})', f'Put Sum ({self.units_str})',
7171
f'Difference ({self.units_str})',
7272
f'Call Boundary ({self.units_str})', f'Put Boundary ({self.units_str})', 'Call ITM', 'Put ITM')
73-
self.session: requests.Session = requests.Session()
74-
self.cookies: Dict[str, str] = {}
7573
self.toaster: win10toast.ToastNotifier = win10toast.ToastNotifier() if is_windows_10_or_11 else None
7674
self.get_icon()
7775
self.login_win(window)
@@ -88,41 +86,23 @@ def create_error_window(error_window: Tk):
8886
error_window.destroy()
8987

9088
try:
91-
symbols_information: requests.Response = requests.get(self.url_symbols, headers=self.headers)
89+
request: requests.Response = self.session.get(self.url_oc, headers=self.headers, timeout=5)
90+
self.cookies = dict(request.cookies)
91+
response: requests.Response = self.session.get(self.url_symbols, headers=self.headers, timeout=5,
92+
cookies=self.cookies)
9293
except Exception as err:
9394
print(err, sys.exc_info()[0], "19")
9495
create_error_window(window)
9596
sys.exit()
96-
symbols_information_soup: bs4.BeautifulSoup = bs4.BeautifulSoup(symbols_information.content, "html.parser")
9797
try:
98-
symbols_table: bs4.element.Tag = symbols_information_soup.findChildren('table')[0]
99-
except IndexError as err:
98+
json_data: Dict[str, Dict[str, List[Dict[str, Union[str, int]]]]] = response.json()
99+
except Exception as err:
100+
print(response)
100101
print(err, sys.exc_info()[0], "20")
101102
create_error_window(window)
102103
sys.exit()
103-
symbols_table_rows: List[bs4.element.Tag] = list(symbols_table.findChildren(['th', 'tr']))
104-
symbols_table_rows_str: List[str] = ['' for _ in range(len(symbols_table_rows) - 1)]
105-
for column in range(len(symbols_table_rows) - 1):
106-
symbols_table_rows_str[column] = str(symbols_table_rows[column])
107-
divider_row: str = '<tr>\n' \
108-
'<td colspan="3"><strong>Derivatives on Individual Securities</strong></td>\n' \
109-
'</tr>'
110-
for column in range(4, symbols_table_rows_str.index(divider_row) + 1):
111-
cells: bs4.element.ResultSet = symbols_table_rows[column].findChildren('td')
112-
column: int = 0
113-
for cell in cells:
114-
if column == 2:
115-
self.indices.append(cell.string)
116-
column += 1
117-
for column in reversed(range(symbols_table_rows_str.index(divider_row) + 1)):
118-
symbols_table_rows.pop(column)
119-
for row in symbols_table_rows:
120-
cells: bs4.element.ResultSet = row.findChildren('td')
121-
column: int = 0
122-
for cell in cells:
123-
if column == 2:
124-
self.stocks.append(cell.string)
125-
column += 1
104+
self.indices = [item['symbol'] for item in json_data['data']['IndexList']]
105+
self.stocks = [item['symbol'] for item in json_data['data']['UnderlyingList']]
126106

127107
def get_icon(self) -> None:
128108
self.icon_png_path: str
@@ -331,7 +311,6 @@ def get_data(self, event: Optional[Event] = None) -> Optional[Tuple[Optional[req
331311
return self.get_data_refresh()
332312

333313
def get_data_first_run(self) -> Optional[Tuple[Optional[requests.Response], Any]]:
334-
request: Optional[requests.Response] = None
335314
response: Optional[requests.Response] = None
336315
self.units_str = 'in K' if self.option_mode == 'Index' else 'in 10s'
337316
self.output_columns: Tuple[str, str, str, str, str, str, str, str, str] = (
@@ -354,11 +333,8 @@ def get_data_first_run(self) -> Optional[Tuple[Optional[requests.Response], Any]
354333

355334
url: str = self.url_index + self.index if self.option_mode == 'Index' else self.url_stock + self.stock
356335
try:
357-
request = self.session.get(self.url_oc, headers=self.headers, timeout=5)
358-
self.cookies = dict(request.cookies)
359336
response = self.session.get(url, headers=self.headers, timeout=5, cookies=self.cookies)
360337
except Exception as err:
361-
print(request)
362338
print(response)
363339
print(err, sys.exc_info()[0], "1")
364340
messagebox.showerror(title="Error", message="Error in fetching dates.\nPlease retry.")
@@ -367,7 +343,7 @@ def get_data_first_run(self) -> Optional[Tuple[Optional[requests.Response], Any]
367343
self.date_menu.config(values=tuple(self.dates))
368344
self.date_menu.current(0)
369345
return
370-
json_data: Any
346+
json_data: Dict[str, Any]
371347
if response is not None:
372348
try:
373349
json_data = response.json()
@@ -541,8 +517,6 @@ def change_option_mode(self) -> None:
541517
self.index_menu.config(state='readonly')
542518
self.stock_menu.config(state=DISABLED)
543519

544-
self.get_data()
545-
546520
self.config_parser.set('main', 'option_mode', f'{self.option_mode}')
547521
with open('NSE-OCA.ini', 'w') as f:
548522
self.config_parser.write(f)

0 commit comments

Comments
 (0)