cfweb

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 29, 2025 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package cfweb provides web scraping and submission for Codeforces

Index

Constants

View Source
const (
	BaseURL       = "https://codeforces.com"
	UserAgent     = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
	SessionExpiry = 24 * time.Hour
	MaxPageSize   = 5 * 1024 * 1024 // 5MB max page size to prevent OOM
)

Variables

View Source
var CurrentSelectors = Selectors{
	Problem: ProblemSelectors{
		Title:        ".problem-statement .title",
		TimeLimit:    ".problem-statement .time-limit",
		MemoryLimit:  ".problem-statement .memory-limit",
		Statement:    ".problem-statement",
		InputSpec:    ".problem-statement .input-specification",
		OutputSpec:   ".problem-statement .output-specification",
		Note:         ".problem-statement .note",
		SampleTests:  ".sample-tests",
		SampleInput:  ".sample-tests .input pre",
		SampleOutput: ".sample-tests .output pre",
		Tags:         ".tag-box",
		Rating:       "span.tag-box[title='Difficulty']",
	},
	Login: LoginSelectors{
		Form:          "form#enterForm, form.enter-form",
		HandleOrEmail: "input[name='handleOrEmail']",
		Password:      "input[name='password']",
		CSRFToken:     "input[name='csrf_token'], meta[name='X-Csrf-Token']",
		Remember:      "input[name='remember']",
		SubmitButton:  "input[type='submit']",
	},
	Submit: SubmitSelectors{
		Form:           "form.submit-form",
		ProblemIndex:   "select[name='submittedProblemIndex'], input[name='submittedProblemIndex']",
		LanguageSelect: "select[name='programTypeId']",
		SourceCode:     "textarea[name='source'], #sourceCodeTextarea",
		CSRFToken:      "input[name='csrf_token']",
		SubmitButton:   "input[type='submit']",
		FTAA:           "input[name='ftaa']",
		BFAA:           "input[name='bfaa']",
	},
	Contest: ContestSelectors{
		ProblemList:    ".problems",
		ProblemRow:     ".problems tr",
		ProblemLink:    "td.id a",
		ProblemName:    "td a",
		StandingsTable: ".standings",
	},
}

CurrentSelectors returns the current set of selectors

View Source
var CurrentVersion = SelectorVersion{
	Version:     "2024.12",
	ValidFrom:   "2024-12-01",
	ValidUntil:  "",
	Description: "CF selectors as of December 2024",
}

CurrentVersion returns the current selector version

View Source
var SupportedLanguages = []Language{
	{ID: "cpp17", Name: "GNU G++17 7.3.0", Extension: ".cpp", CompilerID: 54},
	{ID: "cpp20", Name: "GNU G++20 11.2.0 (64 bit)", Extension: ".cpp", CompilerID: 89},
	{ID: "cpp23", Name: "GNU G++23 14.2 (64 bit)", Extension: ".cpp", CompilerID: 91},
	{ID: "python3", Name: "Python 3.8.10", Extension: ".py", CompilerID: 31},
	{ID: "pypy3", Name: "PyPy 3.10 (7.3.15)", Extension: ".py", CompilerID: 70},
	{ID: "java17", Name: "Java 17 64bit", Extension: ".java", CompilerID: 87},
	{ID: "java21", Name: "Java 21 64bit", Extension: ".java", CompilerID: 88},
	{ID: "go", Name: "Go 1.22.2", Extension: ".go", CompilerID: 32},
	{ID: "rust", Name: "Rust 1.75.0 (2021)", Extension: ".rs", CompilerID: 75},
	{ID: "kotlin", Name: "Kotlin 1.9.21", Extension: ".kt", CompilerID: 83},
	{ID: "csharp", Name: "C# 10, .NET SDK 6.0", Extension: ".cs", CompilerID: 79},
	{ID: "ruby", Name: "Ruby 3.2.2", Extension: ".rb", CompilerID: 67},
	{ID: "js", Name: "JavaScript V8 4.8.0", Extension: ".js", CompilerID: 34},
	{ID: "php", Name: "PHP 8.1.7", Extension: ".php", CompilerID: 6},
	{ID: "haskell", Name: "Haskell GHC 8.10.1", Extension: ".hs", CompilerID: 12},
	{ID: "scala", Name: "Scala 2.12.8", Extension: ".scala", CompilerID: 20},
}

SupportedLanguages lists all supported languages for submission

Functions

func GetHTMLDocument

func GetHTMLDocument(r io.Reader) (*html.Node, error)

GetHTMLDocument parses HTML into a document

Types

type ContestSelectors

type ContestSelectors struct {
	ProblemList    string
	ProblemRow     string
	ProblemLink    string
	ProblemName    string
	StandingsTable string
}

ContestSelectors for contest page

type Language

type Language struct {
	ID         string
	Name       string
	Extension  string
	CompilerID int
}

Language represents a programming language

func GetLanguageByCompilerID

func GetLanguageByCompilerID(compilerID int) *Language

GetLanguageByCompilerID returns language info by compiler ID

func GetLanguageByExtension

func GetLanguageByExtension(ext string) *Language

GetLanguageByExtension returns language info by file extension

func GetLanguageByID

func GetLanguageByID(id string) *Language

GetLanguageByID returns language info by ID

type LoginSelectors

type LoginSelectors struct {
	Form          string
	HandleOrEmail string
	Password      string
	CSRFToken     string
	Remember      string
	SubmitButton  string
}

LoginSelectors for login page

type ParsedProblem

type ParsedProblem struct {
	ContestID   int
	Index       string
	Name        string
	TimeLimit   string
	MemoryLimit string
	Statement   string
	InputSpec   string
	OutputSpec  string
	Note        string
	Samples     []Sample
	Tags        []string
	Rating      int
	URL         string
}

ParsedProblem contains parsed problem data

func (*ParsedProblem) ToSchemaProblem

func (p *ParsedProblem) ToSchemaProblem() *v1.Problem

ToSchemaProblem converts ParsedProblem to schema v1 Problem

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

Parser scrapes problem data from CF web pages

func NewParser

func NewParser(session *Session) *Parser

NewParser creates a new parser

func NewParserWithClient

func NewParserWithClient(client *http.Client) *Parser

NewParserWithClient creates a parser with a custom HTTP client

func (*Parser) ParseContestProblems

func (p *Parser) ParseContestProblems(contestID int) ([]ParsedProblem, error)

ParseContestProblems parses all problems from a contest

func (*Parser) ParseProblem

func (p *Parser) ParseProblem(contestID int, index string) (*ParsedProblem, error)

ParseProblem parses a problem page

func (*Parser) ParseProblemset

func (p *Parser) ParseProblemset(contestID int, index string) (*ParsedProblem, error)

ParseProblemset parses a problem from the problemset

func (*Parser) VerifyPageStructure

func (p *Parser) VerifyPageStructure() error

VerifyPageStructure checks if the page structure matches expected selectors

type ProblemSelectors

type ProblemSelectors struct {
	// Main content
	Title       string
	TimeLimit   string
	MemoryLimit string
	Statement   string
	InputSpec   string
	OutputSpec  string
	Note        string

	// Sample tests
	SampleTests  string
	SampleInput  string
	SampleOutput string

	// Tags and rating
	Tags   string
	Rating string
}

ProblemSelectors for problem page parsing

type Sample

type Sample struct {
	Index  int
	Input  string
	Output string
}

Sample represents a test case

type SelectorVersion

type SelectorVersion struct {
	Version     string
	ValidFrom   string // Date when these selectors became valid
	ValidUntil  string // Empty if current
	Description string
}

SelectorVersion represents a versioned set of CSS selectors When CF changes their HTML structure, we add a new version

type Selectors

type Selectors struct {
	// Problem page selectors
	Problem ProblemSelectors

	// Login page selectors
	Login LoginSelectors

	// Submit page selectors
	Submit SubmitSelectors

	// Contest page selectors
	Contest ContestSelectors
}

Selectors contains all CSS selectors for scraping CF pages

type Session

type Session struct {
	// contains filtered or unexported fields
}

Session manages CF web authentication using pre-extracted cookies No login functionality - users extract cookies from browser

func NewSession

func NewSession() (*Session, error)

NewSession creates a new CF session

func NewSessionWithUserAgent

func NewSessionWithUserAgent(ua string) (*Session, error)

NewSessionWithUserAgent creates a new CF session with custom User-Agent This is important for Cloudflare bypass - the User-Agent MUST match the one used to obtain the cf_clearance cookie

func (*Session) CFClearanceExpiresAt

func (s *Session) CFClearanceExpiresAt() time.Time

CFClearanceExpiresAt returns when cf_clearance expires

func (*Session) CFClearanceExpiresIn

func (s *Session) CFClearanceExpiresIn() time.Duration

CFClearanceExpiresIn returns time until cf_clearance expires

func (*Session) Client

func (s *Session) Client() *http.Client

Client returns the underlying HTTP client

func (*Session) ExpiresAt

func (s *Session) ExpiresAt() time.Time

ExpiresAt returns when the session expires

func (*Session) GetCFClearance

func (s *Session) GetCFClearance() string

GetCFClearance returns the current cf_clearance value

func (*Session) GetCSRFToken

func (s *Session) GetCSRFToken() string

GetCSRFToken returns the current CSRF token

func (*Session) GetUserAgent

func (s *Session) GetUserAgent() string

GetUserAgent returns the User-Agent tied to this session

func (*Session) Handle

func (s *Session) Handle() string

Handle returns the configured handle

func (*Session) HasSessionCookies

func (s *Session) HasSessionCookies() bool

HasSessionCookies returns true if session cookies are set

func (*Session) IsAuthenticated

func (s *Session) IsAuthenticated() bool

IsAuthenticated returns true if session has valid cf_clearance and session cookies

func (*Session) IsCFClearanceValid

func (s *Session) IsCFClearanceValid() bool

IsCFClearanceValid returns true if cf_clearance is set and not expired

func (*Session) IsReadyForSubmission

func (s *Session) IsReadyForSubmission() bool

IsReadyForSubmission returns true if session can submit solutions

func (*Session) RefreshCSRFToken

func (s *Session) RefreshCSRFToken() error

RefreshCSRFToken fetches a fresh CSRF token from any CF page

func (*Session) SetCFClearance

func (s *Session) SetCFClearance(clearance, userAgent string, expiresAt time.Time)

SetCFClearance sets the cf_clearance cookie for Cloudflare bypass The userAgent parameter MUST match the User-Agent used to obtain the cookie

func (*Session) SetFullAuth

func (s *Session) SetFullAuth(cfClearance, userAgent string, cfClearExp time.Time,
	jsessionID, ce7Cookie, handle string)

SetFullAuth sets all authentication cookies at once (cf_clearance + session) This is the primary method for cookie-based auth

func (*Session) SetSessionCookies

func (s *Session) SetSessionCookies(jsessionID, ce7Cookie, handle string)

SetSessionCookies sets session cookies directly (extracted from browser)

func (*Session) Validate

func (s *Session) Validate() error

Validate checks if the session is still valid by verifying handle appears on CF

type SubmissionResult

type SubmissionResult struct {
	SubmissionID int64
	ContestID    int
	ProblemIndex string
	Verdict      string
	Time         time.Duration
	Memory       int64 // bytes
	PassedTests  int
	SubmittedAt  time.Time
	Status       string
}

SubmissionResult contains the result of a submission

type SubmitSelectors

type SubmitSelectors struct {
	Form           string
	ProblemIndex   string
	LanguageSelect string
	SourceCode     string
	CSRFToken      string
	SubmitButton   string
	FTAA           string
	BFAA           string
}

SubmitSelectors for submit page

type Submitter

type Submitter struct {
	// contains filtered or unexported fields
}

Submitter handles solution submission to CF

func NewSubmitter

func NewSubmitter(session *Session) (*Submitter, error)

NewSubmitter creates a new submitter with an authenticated session Requires session to have cf_clearance + session cookies set

func (*Submitter) GetSubmission

func (s *Submitter) GetSubmission(submissionID int64, contestID int) (*SubmissionResult, error)

GetSubmission gets a specific submission's status

func (*Submitter) Submit

func (s *Submitter) Submit(contestID int, problemIndex string, langID int, sourceCode string) (*SubmissionResult, error)

Submit submits a solution to a problem

func (*Submitter) SubmitToGym

func (s *Submitter) SubmitToGym(gymID int, problemIndex string, langID int, sourceCode string) (*SubmissionResult, error)

SubmitToGym submits a solution to a gym problem

func (*Submitter) VerifySubmitPage

func (s *Submitter) VerifySubmitPage(contestID int) error

VerifySubmitPage checks if the submit page structure is valid

func (*Submitter) WaitForVerdict

func (s *Submitter) WaitForVerdict(submissionID int64, contestID int, timeout time.Duration) (*SubmissionResult, error)

WaitForVerdict waits for the submission to be judged

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL