#lang racket (require html-parsing net/http-easy sxml webscraperhelper threading) (struct achievement (completed? title description) #:transparent) (define (input-port->achievements ip) (for/list ([a (get-achievement-tree (html->xexp ip))]) (achievement (get-achievement-completion a) (get-achievement-title a) (get-achievement-description a)))) (define (string-list->string ls) (string-join (filter non-empty-string? (map string-trim ls)) " ")) (define get-achievement-tree (sxpath "//div[contains(@class, 'achieve-item')]")) (define get-achievement-completion (compose1 (curryr set-member? "achieved") list->set string-split car (sxpath '(// @ class *text*)))) (define get-achievement-description (compose1 string-list->string (sxpath '(// *text*)))) (define get-achievement-title (compose1 string-list->string (sxpath '(// @ title *text*)))) (module+ main (command-line #:args (user) (for ([a (input-port->achievements (open-input-bytes (response-body (get (format "https://hardfought.org/tnnt/players/~a.html" user) #:timeouts (make-timeout-config #:lease 20 #:connect 20 #:request 20)))))]) (match-define (struct* achievement ([completed? completed?] [title title] [description description])) a) (printf "~a :: ~a\n" (if completed? "X" "O") title) (printf " ~a\n" description))))