play 2.3 で securesocial3.0 を使う

公式のドキュメントが古いので、使い方をまとめる。

手順

  1. securesocialを導入する
  2. 設定

1.導入

1.1 build.sbt の libraryDependencies に securesocialを追加
libraryDependencies ++= Seq(
  ...
  "securesocial" %% "securesocial" % "3.0-M3" ,
  ...
)
conf/routes に securesocial のルーティングを追加
...
->         /auth                securesocial.Routes
...
1.3 conf/play.plugins に mail plugin を追加
...
1500:com.typesafe.plugin.CommonsMailerPlugin
...

優先度は状況に応じて
oauthのみを使う場合は特に追加する必要はありません

2.設定

2.1 conf/securesocial.conf

securesocial.confの記述は以前のドキュメントと変わらないので、http://securesocial.ws/guide/configuration.htmlを参考に
用意したら conf/application.conf に include

include "securesocial.conf"
2.2 Global.scala に 自前のRuntimeEnvironmentを作成

サンプルプロジェクトを参考に(コピペ)

object Global extends play.api.GlobalSettings {

  /**
   * The runtime environment for this sample app.
   */
  object MyRuntimeEnvironment extends RuntimeEnvironment.Default[DemoUser] {
    override implicit val executionContext = play.api.libs.concurrent.Execution.defaultContext
    override lazy val routes = new CustomRoutesService()
    override lazy val userService: InMemoryUserService = new InMemoryUserService()
    override lazy val eventListeners = List(new MyEventListener())
    override lazy val providers = ListMap(
      include(new TwitterProvider(routes, cacheService, oauth1ClientFor(TwitterProvider.Twitter)))
    )
  }

  /**
   * An implementation that checks if the controller expects a RuntimeEnvironment and
   * passes the instance to it if required.
   *
   * This can be replaced by any DI framework to inject it differently.
   *
   * @param controllerClass
   * @tparam A
   * @return
   */
  override def getControllerInstance[A](controllerClass: Class[A]): A = {
    val instance = controllerClass.getConstructors.find { c =>
      val params = c.getParameterTypes
      params.length == 1 && params(0) == classOf[RuntimeEnvironment[DemoUser]]
    }.map {
      _.asInstanceOf[Constructor[A]].newInstance(MyRuntimeEnvironment)
    }
    instance.getOrElse(super.getControllerInstance(controllerClass))
  }
}

既存のものをカスタマイズしたいときはRuntimeEnvironmentのフィールドをoverrideして書き換えてください。
e.g. viewを自前のものに置き換えたいなら、

override lazy val viewTemplates = new MyViewTemplates

securesocial/RuntimeEnvironment.scala at master · jaliss/securesocial · GitHub
実際にコードを見ながらのほうがわかりやすいかと思います。

自前のproviderを使いたいなら、
https://gist.github.com/krrrr38/d709ca3a8cf92e4294b7
を参考に

play.api.libs.json.JsonでオブジェクトをJson化

case class Human(lastName: String, firstName: String, age: Int)

こいつをJsonに変換しようと思います。

結果からいうとこういうソースになります。

case class Human(lastName: String, firstName: String, age: Int) {
  implicit val humanWrites = new Writes[Human] {
    def writes(human: Human) = Json.obj(
      "first" -> human.firstName,
      "last" -> human.lastName,
      "age" -> human.age
    )
  }
  def toJson = Json.stringify(Json.toJson(this))
}

まずはコンバーターを用意する。

implicit val humanWrites = new Writes[Human] {
  def writes(human: Human) = Json.obj(
    "first" -> human.firstName,
    "last" -> human.lastName,
    "age" -> human.age
  )
}

そしたらJson.toJsonでJsValueに変換した後、Json.stringifyで文字列に変換

def toJson = Json.stringify(Json.toJson(this))

Json化したらPOSTするなりなんなりと。

val h = new Human("koya", "fukushi", 20)
val url = "http://hogehoge.com"
WS.url(url).withHeaders("Content-Type" -> "application/json").post(h.toJson)


詳細は
https://www.playframework.com/documentation/ja/2.3.x/ScalaJson

Scalaでpostリクエスト

actorでpostしたいと思って、ぐぐったらまっさきにこれが出てきた。
http://alvinalexander.com/scala/scala-http-post-json-gson-restful-client-example

apache httpclient を使っている。しかし、少し回りくどい気がする。。。

そこで、もう少し探していたら
ScalaWS
いい感じのがあるじゃないか。

WS.url(url).withHeaders("Content-Type" -> "application/json").post(Json.stringify(product.toJson))

pythonのrequestsでfc2動画にログインする

fc2動画のリンク切れチェックのために、ログインして動画のページをスクレイピングする必要があったので、めも

Python Requests and persistent sessions - Stack Overflow

ようはここを見ろと

import requests
session
def loginToFc2():
	global session
	if session is None:
		session = requests.session()
		login_data = {'email': 'your@mail.com', 'pass': 'your_pass'}
		session.post('https://secure.id.fc2.com/index.php?mode=login&switch_language=en', login_data)
	return session

if __name__ == '__main__':
	session = loginToFc2()
	request = session.get("http://video.fc2.com/en/content/20140516Q6YBtKyM")
	#print request.content
	#後は煮るなり焼くなり

こんな感じでrequests.getの代わりに、sessionを初期化して、session.getのように使えば良い

play のコンパイル時にエラー

[info] LESS compiling on 3 source(s)
[error] [object Object] (/Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js#594)	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js:594 (anonymous)
[error] 	at /Users/koya/dev/nudele/nudele/project/target/less/sbt-less-1.0.0.jar:77 (anonymous)
[error] 	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js:659 (anonymous)
[error] 	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/import-visitor.js:25 (anonymous)
[error] 	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js:664 (anonymous)
[error] 	at /Users/koya/dev/nudele/nudele/project/target/less/sbt-less-1.0.0.jar:58 (anonymous)
[error] 	at /Users/Apigee/src/noderunner/node10/node10src/src/main/javascript/io/apigee/trireme/node10/node/fs.js:266 (anonymous)
[error] 	at /Users/Apigee/src/noderunner/node10/node10src/src/main/javascript/io/apigee/trireme/node10/node/fs.js:107 (anonymous)
[error] 	at /Users/Apigee/src/noderunner/node10/node10src/src/main/javascript/io/apigee/trireme/node10/main/trireme.js:805 (submitTick)
[info]
[trace] Stack trace suppressed: run last web-assets:less for the full output.
[error] (web-assets:less) com.typesafe.sbt.jse.SbtJsTask$JsTaskFailure: [object Object] (/Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js#594)	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js:594 (anonymous)
[error] 	at /Users/koya/dev/nudele/nudele/project/target/less/sbt-less-1.0.0.jar:77 (anonymous)
[error] 	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js:659 (anonymous)
[error] 	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/import-visitor.js:25 (anonymous)
[error] 	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js:664 (anonymous)
[error] 	at /Users/koya/dev/nudele/nudele/project/target/less/sbt-less-1.0.0.jar:58 (anonymous)
[error] 	at /Users/Apigee/src/noderunner/node10/node10src/src/main/javascript/io/apigee/trireme/node10/node/fs.js:266 (anonymous)
[error] 	at /Users/Apigee/src/noderunner/node10/node10src/src/main/javascript/io/apigee/trireme/node10/node/fs.js:107 (anonymous)
[error] 	at /Users/Apigee/src/noderunner/node10/node10src/src/main/javascript/io/apigee/trireme/node10/main/trireme.js:805 (submitTick)
[error] application -

! @6l9n8hn08 - Internal server error, for (GET) [/] ->

play.PlayExceptions$UnexpectedException: Unexpected exception[JsTaskFailure: [object Object] (/Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js#594)	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js:594 (anonymous)
	at /Users/koya/dev/nudele/nudele/project/target/less/sbt-less-1.0.0.jar:77 (anonymous)
	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js:659 (anonymous)
	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/import-visitor.js:25 (anonymous)
	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js:664 (anonymous)
	at /Users/koya/dev/nudele/nudele/project/target/less/sbt-less-1.0.0.jar:58 (anonymous)
	at /Users/Apigee/src/noderunner/node10/node10src/src/main/javascript/io/apigee/trireme/node10/node/fs.js:266 (anonymous)
	at /Users/Apigee/src/noderunner/node10/node10src/src/main/javascript/io/apigee/trireme/node10/node/fs.js:107 (anonymous)
	at /Users/Apigee/src/noderunner/node10/node10src/src/main/javascript/io/apigee/trireme/node10/main/trireme.js:805 (submitTick)
]
	at play.PlayReloader$$anon$1$$anonfun$play$PlayReloader$$anon$$taskFailureHandler$1.apply(PlayReloader.scala:237) ~[na:na]
	at play.PlayReloader$$anon$1$$anonfun$play$PlayReloader$$anon$$taskFailureHandler$1.apply(PlayReloader.scala:230) ~[na:na]
	at scala.Option.map(Option.scala:145) ~[scala-library-2.11.5.jar:na]
	at play.PlayReloader$$anon$1.play$PlayReloader$$anon$$taskFailureHandler(PlayReloader.scala:230) ~[na:na]
	at play.PlayReloader$$anon$1$$anonfun$reload$2.apply(PlayReloader.scala:90) ~[na:na]
Caused by: com.typesafe.sbt.jse.SbtJsTask$JsTaskFailure: [object Object] (/Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js#594)	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js:594 (anonymous)
	at /Users/koya/dev/nudele/nudele/project/target/less/sbt-less-1.0.0.jar:77 (anonymous)
	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js:659 (anonymous)
	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/import-visitor.js:25 (anonymous)
	at /Users/koya/dev/nudele/nudele/project/target/node-modules/webjars/less/lib/less/parser.js:664 (anonymous)
	at /Users/koya/dev/nudele/nudele/project/target/less/sbt-less-1.0.0.jar:58 (anonymous)
	at /Users/Apigee/src/noderunner/node10/node10src/src/main/javascript/io/apigee/trireme/node10/node/fs.js:266 (anonymous)
	at /Users/Apigee/src/noderunner/node10/node10src/src/main/javascript/io/apigee/trireme/node10/node/fs.js:107 (anonymous)
	at /Users/Apigee/src/noderunner/node10/node10src/src/main/javascript/io/apigee/trireme/node10/main/trireme.js:805 (submitTick)

	at com.typesafe.sbt.jse.SbtJsTask$$anonfun$com$typesafe$sbt$jse$SbtJsTask$$executeJsOnEngine$1.apply(SbtJsTask.scala:195) ~[na:na]
	at com.typesafe.sbt.jse.SbtJsTask$$anonfun$com$typesafe$sbt$jse$SbtJsTask$$executeJsOnEngine$1.apply(SbtJsTask.scala:167) ~[na:na]
	at scala.util.Success$$anonfun$map$1.apply(Try.scala:206) ~[scala-library-2.11.5.jar:na]
	at scala.util.Try$.apply(Try.scala:161) ~[scala-library-2.11.5.jar:na]
	at scala.util.Success.map(Try.scala:206) ~[scala-library-2.11.5.jar:na]

上のようなエラーが出た

JsTaskFailure while less compilation · Issue #2662 · playframework/playframework · GitHub

参考にしたら治った。

Beautiful soup 同じ階層の要素を列挙

現在の階層からルートまで検索したい時があったので

while elm is not None:
	for next in elm.next_siblings:
		print next.name

	for prev in elm.previous_siblings:
		print prev.name

	elm = elm.parent
	if elm is not None:
		print elm.name

1.後の要素をすべて列挙
2.前の要素をすべて列挙
3.一つ上の階層に移動
4.1に戻る