Skip to content

Commit

Permalink
Fix login; Add suppport for extract CAUTH from browser cookie; Add su…
Browse files Browse the repository at this point in the history
…pport for login by browser
  • Loading branch information
csyezheng committed Oct 14, 2023
1 parent f80d70c commit 61c7dc0
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 10 deletions.
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
+ [Installation (recommended)](#installation-recommended)
+ [Manual Installation](#manual-installation)
+ [Docker container](#docker-container)
* [Before the start](#before-the-start)
* [Quick Start](#quick-start)
+ [Examples](#examples)
* [Troubleshooting](#troubleshooting)
Expand Down Expand Up @@ -55,6 +56,32 @@ docker run --rm -it -v \
coursera-helper/coursera_helper -u <USER> -p <PASSWORD>
```

## Before the start

`coursera-helper` supports four authentication methods:

1. **CAUTH (recommended)**

Just use the `--cauth 'CAUTH-value-from-browser'` option when running the program.

[How to get the cauth value?](#CAUTH)

2. Browser cookies

Just use the `--browser-cookie` option when running the program.

Automatically extract CAUTH value from the browser cookie. If this method fails, please use other authentication methods.

3. Username and Password

Just use the `-u <user> -p <pass>` options when running the program.

Please note that this method will open the browser, you may have to click on the reCAPTCHA.

4. netrc File

Just use the `--netrc` options when running the program.

## Quick Start

Run the following command to query the usage and options:
Expand Down Expand Up @@ -133,6 +160,42 @@ coursera-helper data-analysis-with-python

## Troubleshooting

### CAUTH

Find your coursera CAUTH:

* Open and login to https://www.coursera.org/
* Right-click on the touchpad or mouse until you find *inspect*.
* Go to Applications > Cookies (and click dropdown) > click https://www.coursera.org/ > find and click CAUTH > Copy value CAUTH.

**Chrome**:

1. Open the browser and login to https://www.coursera.org/

2. Open the last DevTools panel

Windows or Linux: Press **F12** on the keyboard. Or press the **Ctrl** + **Shift** + **I** keys.

Mac: Press **Fn** + **F12** on the keyboard. Or press the **Cmd** + **Option** + **I** keys.

3. Open **Application** > **Storage** > **Cookies** and select https://www.coursera.org/.

4. find and click CAUTH > Copy value CAUTH

**Firefox **:

1. Open the browser and login to https://www.coursera.org/

2. Open the last DevTools panel

Windows or Linux: Press **F12** on the keyboard. Or press the **Ctrl** + **Shift** + **I** keys.

Mac: Press **Fn** + **F12** on the keyboard. Or press the **Cmd** + **Option** + **I** keys.

3. Open **Storage** > **Cookies** and select https://www.coursera.org/.

4. find and click CAUTH > Copy value CAUTH

### china-issues

If you are from China and you're having problems downloading videos, adding
Expand Down
2 changes: 1 addition & 1 deletion coursera_helper/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.11.93'
__version__ = '0.12.1'
66 changes: 66 additions & 0 deletions coursera_helper/cauth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import logging
import sys
import random
import platform
import browser_cookie3
from playwright.sync_api import sync_playwright


def cauth_by_login(username, password, headless=True):
with sync_playwright() as playwright:
try:
if platform.system() == 'Windows':
browser = playwright.chromium.launch(channel="msedge", headless=headless)
elif platform.system() == 'Linux':
browser = playwright.firefox.launch(headless=headless)
elif platform.system() == 'Darwin':
browser = playwright.webkit.launch(headless=headless)
else:
browser = playwright.chromium.launch(channel="chrome", headless=headless)
except AttributeError:
logging.info('Please run "playwright install" in terminal and then try again!')
sys.exit()

context = browser.new_context(
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/117.0.0.0 Safari/537.36',
)
context.add_init_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")

page = context.new_page()

page.goto("https://www.coursera.org/", timeout=0)
page.click('a[href*="/?authMode=login"]')

email_elem = page.locator('#email')
password_elem = page.locator('#password')

email_elem.press_sequentially(username, delay=random.random() * 1000)
password_elem.press_sequentially(password, delay=random.random() * 1000)

page.locator('button[type*="submit"]').click()

page.wait_for_selector('p[data-e2e="UserPortraitFullName"]', timeout=0)

cookies = context.cookies('https://www.coursera.org/')
cauth = ''
cookie_dict = {cookie['name']: cookie['value'] for cookie in cookies}
if 'CAUTH' in cookie_dict:
cauth = cookie_dict['CAUTH']
browser.close()
return cauth


def cauth_by_cookie():
domain = 'coursera.org'
browsers = ['chrome', 'chromium', 'edge', 'firefox', 'safari']
for browser in browsers:
try:
statement = 'browser_cookie3.{}(domain_name="{}")'.format(browser, domain)
cookies = eval(statement)
cookie_dict = {cookie.name: cookie.value for cookie in cookies}
if 'CAUTH' in cookie_dict:
cauth = cookie_dict['CAUTH']
return cauth
except browser_cookie3.BrowserCookieError:
pass
18 changes: 17 additions & 1 deletion coursera_helper/commandline.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,22 @@ def parse_args(args=None):
help='uses or creates local cached version of syllabus'
' page')

parser.add_argument(
'--browser-cookie',
dest='browser_cookie',
action='store_true',
default=False,
help='Extract CAUTH value from cookies of browser'
' (default: False)')

parser.add_argument(
'--headless',
dest='headless',
action='store_true',
default=False,
help='Whether to run browser in headless mode'
' (default: False)')

# Final parsing of the options
args = parser.parse_args(args)

Expand Down Expand Up @@ -500,7 +516,7 @@ def parse_args(args=None):
logging.error('Cookies file not found: %s', args.cookies_file)
sys.exit(1)

if not args.cookies_file and not args.cookies_cauth:
if not args.cookies_file and not args.cookies_cauth and not args.browser_cookie:
try:
args.username, args.password = get_credentials(
username=args.username, password=args.password,
Expand Down
25 changes: 17 additions & 8 deletions coursera_helper/coursera_dl.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
from .network import get_page, get_page_and_url
from .commandline import parse_args
from .extractors import CourseraExtractor
from coursera_helper.cauth import cauth_by_login, cauth_by_cookie

from coursera_helper import __version__

Expand All @@ -97,15 +98,16 @@ def get_session():
return session


def list_courses(args):
def list_courses(session, args):
"""
List enrolled courses.
@param session: session.
@type session: session
@param args: Command-line arguments.
@type args: namedtuple
"""
session = get_session()
login(session, args.username, args.password)
extractor = CourseraExtractor(session)
courses = extractor.list_courses()
logging.info('Found %d courses', len(courses))
Expand Down Expand Up @@ -227,16 +229,23 @@ def main():
mkdir_p(PATH_CACHE, 0o700)
if args.clear_cache:
shutil.rmtree(PATH_CACHE)
if args.list_courses:
logging.info('Listing enrolled courses')
list_courses(args)
return

session = get_session()
if args.cookies_cauth:
session.cookies.set('CAUTH', args.cookies_cauth)
elif args.browser_cookie:
cauth = cauth_by_cookie()
session.cookies.set('CAUTH', cauth)
else:
login(session, args.username, args.password)
cauth = cauth_by_login(args.username, args.password, headless=args.headless)
session.cookies.set('CAUTH', cauth)
# login(session, args.username, args.password)

if args.list_courses:
logging.info('Listing enrolled courses')
list_courses(session, args)
return

if args.specialization:
args.class_names = expand_specializations(session, args.class_names)

Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ dependencies = [
"keyring>=4.0",
"configargparse>=0.12.0",
"attrs==18.1.0",
"playwright>=1.38.0",
"browser_cookie3>=0.19.1",
]

[project.optional-dependencies]
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ pyasn1>=0.1.7
keyring>=4.0
configargparse>=0.12.0
attrs==18.1.0
playwright>=1.38.0
browser_cookie3>=0.19.1

0 comments on commit 61c7dc0

Please sign in to comment.