---
# System prepended metadata

title: book ranking search

---

# book ranking search

```python=
import requests
from bs4 import BeautifulSoup
import re
from datetime import date
import plotly.express as px
import pandas as pd
from functools import reduce


def convert_ranking_data(date_and_ranking):
    date_origin = date.fromisoformat(date_and_ranking[0]["date"])
    date_end = date.fromisoformat(date_and_ranking[-1]["date"])

    print("date origin: %s" % date_origin)
    print("date end: %s" % date_end)

    total_days = ((date_end - date_origin).days + 1)

    print("total days: %d" % total_days)

    ranking_data = [None] * total_days
    for dr in date_and_ranking:
        date_current = date.fromisoformat(dr["date"])
        index = (date_current - date_origin).days
        print("index is %d. len is %d" % (index, len(ranking_data)))
        ranking_data[index] = int(dr["ranking"])

    return ranking_data


def get_ranking(link):
    response = requests.get(link)
    print(response.text)

    soup = BeautifulSoup(response.text)
    tags = soup.find_all("td", string=re.compile("文學新書暢銷榜"))
    date_and_ranking = list(map(lambda x: {"date": x.find_previous_sibling().text, "ranking": x.find_next_sibling().text}, tags))
    print(date_and_ranking)

    date_and_ranking.reverse()

    if len(date_and_ranking) == 0:
        return []

    return convert_ranking_data(date_and_ranking)
    


def fill_entries(arr, target):
    arr.extend([None] * (target - len(arr)))
    return arr


def draw_diagram(data):
    df = pd.DataFrame(data)

    fig = px.line(df)
    fig.update_layout(yaxis = dict(autorange="reversed"))
    fig.write_html('first_figure.html', auto_open=True)


def search():
    site = "https://www.monster101.com"
    url = site + "/s"

    response = requests.post(url, data={"query": "張亦絢"})
    
    print(response.text)

    soup = BeautifulSoup(response.text)

    link_tags = soup.select("td a")

    result = list(map(lambda x: {"name": x.text, "link": site + x.get('href')}, link_tags))

    data = {}
    for r in result:
        ranking_list = get_ranking(r["link"])
        if len(ranking_list) > 0:
            data[r["name"]] = ranking_list

    entries = map(lambda x: len(x), data.values())
    max_entries = reduce(lambda x, y: max(x, y), entries)
    data = {k: fill_entries(v, max_entries) for k, v in data.items()}

    print(data)

    draw_diagram(data)


search()

```