Repository: ranaroussi/yfinance

Issue:
HTTPError: 401 Client Error: Unauthorized for url
I'm on yfinance version 0.2.22 (Python 3.9.10 on macOS 12.6.3), and since today, I keep getting the following error (e.g. on calling `yf.Ticker('AAPL').info`):

`HTTPError: 401 Client Error: Unauthorized for url: https://query2.finance.yahoo.com/v10/finance/quoteSummary/AAPL?modules=summaryProfile%2CfinancialData%2CquoteType%2CdefaultKeyStatistics%2CassetProfile%2CsummaryDetail&ssl=true`

Is this a known/global issue at the moment?

#### @ValueRaider hijacking top post
Please only post if you have something useful


Discussion:
same issue here just now... python 3.10, latest yfinance version, windows...
It seems "v10 quoteSummary" also needs cookie and crumb.
Same here, from yesterday (12th July, 2023)...

I have the same problem...
Yes, witnessing the same problem.
I have the same issue, it came on Thusday, on Wednesday morning my script was working and now again. Hope that can be fixed.
I also have the same problem since this morning. 

 401 Client Error: Unauthorized for url: https://query2.finance.yahoo.com/v10/finance/quoteSummary/EPAM?modules=summaryProfile%2CfinancialData%2CquoteType%2CdefaultKeyStatistics%2CassetProfile%2CsummaryDetail&ssl=true

It would be great if we could find a solution. Thanks!
history work 👍  but not Info 👎 
Well obviously this is a problem. Let's keep thread tidy and constructive now.

@lapis42 You know that because you have it working with cookie and crumb?
If I use the [URL in the original message](https://query2.finance.yahoo.com/v10/finance/quoteSummary/AAPL?modules=summaryProfile%2CfinancialData%2CquoteType%2CdefaultKeyStatistics%2CassetProfile%2CsummaryDetail&ssl=true)

Using `curl` I get:

```{"finance":{"result":null,"error":{"code":"Unauthorized","description":"Invalid Cookie"}}}```

If I do the same in a browser that has a logged in session to Yahoo! finance it returns:

```{"finance":{"result":null,"error":{"code":"Unauthorized","description":"Invalid Crumb"}}}```
@decadecity  I have code that can extract crumb, might help. I've never used it in requests.

``` Python
import requests, re, json
def get_crumb():
    response = requests.get("https://finance.yahoo.com")
    pat = re.compile(r'window\.YAHOO\.context = ({.*?});', re.DOTALL)
    match = re.search(pat, response.text)
    if match:
        js_dict = json.loads(match.group(1))
        return js_dict.get('crumb')
    return None
```
Done a bit of digging around with `curl` and browser requests and as a minimum it seems like it needs the `A1` cookie and the `crumb` URL parameter.
I had already noticed these errors on the infos, when asking for example, for crypto currencies, like BTC-USD
@ValueRaider Yes, I was able to retrieve the data after providing crumb with cookie.
I cannot understand what solution has to be done. Is this solved as I am having the same problem? It says invalid crumb.
@lapis42 @decadecity Could you 2 elaborate on how you obtained and provided cookie & crumb?
I got the cookie by visiting `finances.yahoo.com` in a browser and clicked through the consent dialogue which sends a POST to `consent.yahoo.com` which returns a 302 with the `Set-Cookie` for the `A1`.  I got the crumb from `window.YAHOO.context.crumb` (which I found from your comment).

With those two I could then put them into a command line `curl` and it returned the data:

`curl 'https://query2.finance.yahoo.com/v10/finance/quoteSummary/AAPL?modules=summaryProfile%2CfinancialData%2CquoteType%2CdefaultKeyStatistics%2CassetProfile%2CsummaryDetail&ssl=true&crumb={{ crumb }}'  -H 'cookie: A1={{ A1 cookie }}'`

I've not looked into how to do this in Python.
@decadecity With a basic free Yahoo account?
@ValueRaider Initially yes but once I'd used that to figure out the minimum information required I was able to do it anonymously in a private browsing window with a completely clean session.
@ValueRaider @signifer-geo v0.2.23 is working for me 👍🏻 
Not for me :-( Maybe value is close ???

Resolving patch:
diff --git a/yfinance/scrapers/quote.py b/yfinance/scrapers/quote.py
--- a/yfinance/scrapers/quote.py
+++ b/yfinance/scrapers/quote.py
@@ -586,11 +586,9 @@ def _fetch(self, proxy):
         if self._already_fetched:
             return
         self._already_fetched = True
-        modules = ['summaryProfile', 'financialData', 'quoteType',
-                     'defaultKeyStatistics', 'assetProfile', 'summaryDetail']
+        modules = ['financialData', 'quoteType', 'defaultKeyStatistics', 'assetProfile', 'summaryDetail']
         params_dict = {}
-        for m in modules:
-            params_dict["modules"] = m
+        params_dict["modules"] = modules
         params_dict["ssl"] = "true"
         result = self._data.get_raw_json(
             _BASIC_URL_ + f"/{self._data.ticker}", params=params_dict, proxy=proxy


Test patch:
diff --git a/tests/ticker.py b/tests/ticker.py
--- a/tests/ticker.py
+++ b/tests/ticker.py
@@ -692,7 +692,10 @@ def test_fast_info(self):
     def test_info(self):
         data = self.tickers[0].info
         self.assertIsInstance(data, dict, "data has wrong type")
-        self.assertIn("symbol", data.keys(), "Did not find expected key in info dict")
+        expected_keys = ['industry', 'currentPrice', 'exchange', 'floatShares', 'companyOfficers', 'bid']
+        for k in expected_keys:
+            print(k)
+            self.assertIn("symbol", data.keys(), f"Did not find expected key '{k}' in info dict")
         self.assertEqual(self.symbols[0], data["symbol"], "Wrong symbol value in info dict")
 
     # def test_fast_info_matches_info(self):