Indeedという求人情報のアグリゲーションサイトがある。ここはSEOで相当強いサイトでかつ、使い勝手がよくユーザー数を伸ばしています。当初は無断に求人メディアを転載しているような立ち位置(見方による)だったのですが、今は完全にメディアと立場が逆転しつつあります。
応募者の多くがIndeed経由という形になりつつあり、さらにIndeed経由の応募者を獲得しようとメディアはIndeedの広告枠を日夜ビットしている。そんな中で、Indeedの中でどれだけ上位表示されることができるか(GoogleでのSEOのようなもの)が、メディアの中で重要視されつつある。つまりメディアの先、広告主の中でもIndeedのプレゼンスが高まっているということです。
今回は、「キーワード」「勤務地」「メディア」を入力し、POSTするとIndeedの100位以内の表示にどの程度その「メディア」の求人が掲載されているのかを、リアルタイムにグラフ出力するWebアプリケーションを作りました。
できたもの
必要なもの
- Flask
- BeautifulSoup
- requests
実装について
アプリのファイル構成はこんな感じになっています。
flaskwork
|–main.py
|–requirements.txt
|–static
| |–bootstrap.css
| |–d3.v3.min.js
| |–indeedlogo.png
| |–loader.gif
|–templates
| |–base.html
| |–index.html(初期表示)
| |–result.html(結果表示)
|–Procfile
この中でもmain.pyにルーティングとBeautifulSoupでIndeedスクレイピングする役割を持たせてます。コードも少ない。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# -*- coding: utf-8 -*- from flask import Flask, render_template, request from bs4 import BeautifulSoup import requests import tqdm import os app = Flask(__name__) @app.route('/') def index(): return render_template('index.html') @app.route('/send', methods=['GET', 'POST']) def send(): if request.method == 'POST': query = request.form['query'] location = request.form['location'] media = request.form['media'] counter = count_media(query, location, media) return render_template('result.html', message=counter, queryto=query, locationto=location, mediato=media) else: return render_template('index.html') def indeed_ocupy_getter(query, location): source_list = [] for i in tqdm.tqdm(range(0,150,10)): url = 'https://jp.indeed.com/%E6%B1%82%E4%BA%BA?q={}&l={}&start={}'.format(query, location, i) res = requests.get(url) soup = BeautifulSoup(res.content, 'html.parser') source_name = soup.findAll("span" , {"class": "result-link-source"}) for i in source_name: source_list.append(i.text.replace(' ', '')) return source_list[0:100] def count_media(query, location, media): x = indeed_ocupy_getter(query, location) counter = 0 for p in x: if p == media: counter +=1 return counter |
templateの中にレンダリングさせるhtmlを入れています。base.htmlとindex.htmlは紹介するまでもないです。result.htmlは下記の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
{% extends "base.html" %} {% block content %} <div class="container"> <div style="margin-top:30px;"></div> <table class="table"> <thead class="thead-inverse"> <tr> <th>キーワード</th> <th>勤務地</th> <th>メディア</th> </tr> </thead> <tbody> <tr> <td>{{ queryto }}</td> <td>{{ locationto }}</td> <td>{{ mediato }}</td> </tr> </tbody> </table> <div style="width:100%;"> <div id="donut" style="width:100%;"></div> </div> <div style="margin-bottom:20px;"></div> </div> <script charset="utf-8" src="static/d3.v3.min.js"></script> <script> //表示スクリプト省略 </script> {% endblock %} |
あまりよくないかもしれないですが、result.htmlの最後にグラフ描画用のd3を読み込んで、表示のJSを書き込んでいます。 これでアプリ構成は完了。Herokuへのデプロイは下記のページを参考にさせていただきました。
ZoomやChatworkでファイル共有している方へ
リモートワークが一般的になってきた今「誰が」「どこで」「何を」ファイル共有しているのかしっかりと把握する必要があります。easyDBを利用すればセキュリティ上で安全なファイル共有をクラウド上で行えるだけでなく、ファイルのバージョン管理等も簡単にできます。
>>>リモートワーク時代の安全なファイル共有「easyDB」はこちら