Grab Packt With Groovy

Automatically claim Packt's free e-books with a Groovy program.

Introduction

Packt Publishing has launched a new programme called "free learning offer"; each day they put an e-book for free on their website to download: one only needs to login to Packt's website and click on the "claim your free book" link.

Following Grab Packt with Racket, here is the Groovy version, to automatically add the e-book to your Packt account for later downloads.

The Code

The code is in public domain. You can get it directly from is.gd/isbviw or from my github gist.

For this to work you need to replace YOUR-EMAIL-ADDRESS (line 26) and YOUR-PASSWORD (line 27) with reasonable values. If you wish to run this from shell/cron remember to add #! /usr/bin/env groovy to the top of the file.

The script is completely self-contained as @Grab annotation on line 4 fetches the dependencies it requires.
/**
 * @author Bahman Movaqar 
 */
@Grab('org.jsoup:jsoup:1.8.2')
import static org.jsoup.Jsoup.parse

def cookieManager = new CookieManager(null, CookiePolicy.ACCEPT_ALL)
CookieHandler.setDefault(cookieManager)
def doc = parse(
  new URL('https://www.packtpub.com/packt/offers/free-learning').text
)
2.times { // a weird hack! to make this work on slow connections
  doLogin(
    loginParams(doc.select('input[type=hidden][id^=form][value^=form]')?.val())
  )
}
claimBook(
  doc.select('a.twelve-days-claim').attr('href'),
  CookieHandler.getDefault().cookieStore.cookies
)
println('Claimed! Login to Packt website to download the book.')

///////////////////////////////////////////////////////////////////////////////
def loginParams(formBuildId) {
  [
    email: 'YOUR_EMAIL_ADDRESS',
    password: 'YOUR_PASSWORD',
    op: 'Login', 
    form_id: 'packt_user_login_form',
    form_build_id: formBuildId ?: ''
  ].findAll { k, v -> v }.collect { k, v -> 
    "$k=${URLEncoder.encode(v, 'UTF8')}"
  }.join('&')
}

///////////////////////////////////////////////////////////////////////////////
def doLogin(loginParams) {
  new URL(
    'https://www.packtpub.com/packt/offers/free-learning'
  ).openConnection().with {
    requestMethod = 'POST'
    setRequestProperty('Content-Type', 'application/x-www-form-urlencoded')
    doOutput = true
    doInput = true
    allowUserInteraction = true
    outputStream.withWriter { w -> w << loginParams }
    connect()
    if (parse(inputStream.text).select('div.error'))
      throw new Exception("Failed to login.")
  }
}

///////////////////////////////////////////////////////////////////////////////
def claimBook(bookUrl, cookies) {
  new URL(
    "https://www.packtpub.com${bookUrl}"
  ).openConnection().with {
    requestMethod = 'GET'
    cookies.each { setRequestProperty('Cookie', it.toString()) }
    connect()
    content
  }
}

How To Run

Provided that you have installed Groovy (if you're on Linux/Mac, I'd very strongly suggest doing that with GVMsdkman), get the code by copy-pasting or directly from is.gd/isbviw and simply run (remember to save the file as GrabPackt.groovy):
$ groovy GrabPackt.groovy

Comments

Popular posts from this blog

Variables in GNU Make: Simple and Recursive

Checkmate on Your Terms: A Personal Journey with Correspondence Chess

Firefox profiles: Quickly replicate your settings to any machine