2
\$\begingroup\$

This is a more difficult version of It's a find-a-movie challenge .

Input

Your code should take a BBFC rating and a number from 1 to 5 as input. It can do this in any way you find convenient.

Output

Your code should return the name of any movie which has a) that film rating and b) that number of stars in a Guardian film review.

If there is no such movie it can output anything you like.

The possible BBFC film ratings are U, PG, 12, 12A, 15, 18, R18, TBC.

Your code may report one or more movies, that is up to you.

To clarify, your code is meant to access the web to get the answers to queries.

Example

Say the input is U, 5 then your code could output "My Neighbour Totoro".

Please show an example of your code working with the film rating PG and score 4 along with your answer.

Notes

The Guardian does have an API but this requires registration. For this challenge you may not use it.

Example code

The following Python 3 code gets all the movies along with their score out of 5, although not 100% perfectly.

from bs4 import BeautifulSoup
import requests
import sys

for i in range(1,837):
    print("Page", i,file=sys.stderr)
    result = requests.get("https://www.theguardian.com/film+tone/reviews?page={0}".format(i))
    data = result.text
    soup = BeautifulSoup(data, "lxml")

    tags = soup.find_all("div", {"class":"stars"})

    for tag in tags:
        stars = 0
        for star in tag.find_all("span", {"class":"star__item--grey"}):
            stars +=1
        main = tag.parent
        title = main.find("h2")
        if title:
            a = title.find("span", {"class":"js-headline-text"})
            print("{} - {}".format(5 - stars, a.text))
\$\endgroup\$
0

3 Answers 3

3
+25
\$\begingroup\$

NodeJS

I'm an awful golfer tho

The inputs must be passed like this node filename 12,12A,15,18 4 for fetching a movie with one of the ratings comma separated and at least 4 stars

var fetch=require('node-fetch');
var {JSDOM, VirtualConsole}=require('jsdom');

var f=x=>fetch(x).then(r=>r.text());
var vc = new VirtualConsole(); // ignore annoying css errors
var [bbfc='U,PG,12',stars='3']=process.argv.slice(2);

var Z=async()=>{
    for(var i=0;i<10;i++){ // 10 max pages, can be anything
        var t= await f(`https://www.theguardian.com/film+tone/reviews?page=${i}`);
        var w=new JSDOM(t, {virtualConsole:vc}).window;
        for(var h of w.document.querySelectorAll('.fc-item__header')){
            if (h.querySelectorAll('.star__item--golden').length>=stars){
                var title=h.querySelector('.js-headline-text').textContent.split(' review')[0].trim();
                var t=await f('http://www.bbfc.co.uk/search/releases/'+title);
                var rating=t.match(/BBF\w_(\w+)_/)[1];
                if(bbfc.includes(rating)) return title;
            }
        }
    }
};

Z()
.then(console.log)
.catch(console.error)
\$\endgroup\$
7
  • 2
    \$\begingroup\$ At least you can remove lots of unnecessary whitespaces, and you must also include the bytecount. \$\endgroup\$ Sep 30, 2017 at 15:57
  • \$\begingroup\$ That's 956 bytes, but removing whitespaces could save you some. \$\endgroup\$
    – RedClover
    Sep 30, 2017 at 16:01
  • \$\begingroup\$ It works! However the question asks for exactly the right score, not at least the score. \$\endgroup\$
    – user9206
    Sep 30, 2017 at 17:58
  • \$\begingroup\$ I found a bug I think. Try node caub.js U 4. You get Peter Bradshaw's film of the week Daphne. First, Daphne is rated 15 and second you need to extract the movie name. \$\endgroup\$
    – user9206
    Sep 30, 2017 at 18:22
  • \$\begingroup\$ The code crashes on page 28 with TypeError: Cannot read property '1' of null at Z (/home/foo/caub.js:17:51) at process._tickCallback (internal/process/next_tick.js:109:7) \$\endgroup\$
    – user9206
    Sep 30, 2017 at 21:04
2
\$\begingroup\$

Javascript/JQuery - 517 504 494 bytes

Not really golfed at all, just wanted to write an answer.

x=>y=>{t=n=i=1;f=()=>{if(t){$.get("https://www.theguardian.com/film+tone/reviews?page="+i,d=>{l=$(d).find("div.stars").toArray().slice(1);for(k=0;k<l.length&&t;k++){((j,m)=>($.get('http://www.bbfc.co.uk/search/releases/'+encodeURI(n=$(m[j].parentNode).find("h2 span.js-headline-text").text().split(" review")[0]),(p=>b=>{if(/BBFC_(.*?)_/.exec($(b).find(".symbol img")[0].src)[1]==y&&$(m[j]).find(".star__item--golden").length==x){if(t)alert(p);t=0}})(n))))(k,l)}});i++;setTimeout(f,2000)}};f()}

It waits 10 sec before trying another page to stop the program from doing too many requests concurrently, so it may take some time with some inputs.

Examples:

enter image description here

enter image description here

\$\endgroup\$
9
  • \$\begingroup\$ I don't know JS, but I do know that x=>y=> using currying is a byte shorter than (x,y)=>. \$\endgroup\$
    – LyricLy
    Sep 30, 2017 at 4:07
  • \$\begingroup\$ Thank you for giving the first answer! Is it possible to make a tio.run/# link for it? \$\endgroup\$
    – user9206
    Sep 30, 2017 at 6:13
  • \$\begingroup\$ @Lembik TIO cannot access the internet. Since this is JS, a Stack Snippet could be used, or it's reasonably easy to run the code in your browser's console. \$\endgroup\$
    – LyricLy
    Sep 30, 2017 at 6:50
  • \$\begingroup\$ since when jquery is allowed in golfing? use fetch \$\endgroup\$
    – caub
    Sep 30, 2017 at 12:53
  • \$\begingroup\$ Can you show an example of your code running? I am having no luck getting it to work. My steps: open new tab, press F12, enter f=(x,y)..., f("U",5) . Then f("U",5) gives me TypeError: $.get is not a function [Learn More] \$\endgroup\$
    – user9206
    Sep 30, 2017 at 12:57
1
\$\begingroup\$

Python + BS4 - 631 bytes

Lembik wanted a Python answer so he could run it, so I made one, but its way longer.

from bs4 import BeautifulSoup as b
import requests
def f(x,y):
 i=n=1
 while 1:
  for m in b(requests.get("https://www.theguardian.com/film+tone/reviews?page="+`i`).text,'lxml').find_all('div',{'class':'stars'}):
         a=m.parent.find('h2')
         if a:
          e=a.find('span',{'class':'js-headline-text'}).text.split(" review")[0]
          s=b(requests.get('http://www.bbfc.co.uk/search/releases/'+requests.utils.quote(e)).text,'lxml').find("p",{"class":"symbol"})
          if s and s.find("img").get('src').split("BBFC_")[1].split("_")[0]==y and len(m.find_all('span',{'class':'star__item--golden'}))==x:return e
  i+=1
\$\endgroup\$
4
  • \$\begingroup\$ The code crashes on page 6 with "Traceback (most recent call last): File "guardianfilm-2.py", line 17, in <module> print f(5, "U") File "guardianfilm-2.py", line 13, in f if s and s.find("img").get('src').split("BBFC_")[1].split("_")[0]==y and len(m.find_all('span',{'class':'star__item--golden'}))==x: IndexError: list index out of range " \$\endgroup\$
    – user9206
    Oct 1, 2017 at 9:26
  • \$\begingroup\$ 621 bytes with a bit of reordering and link tweaking. \$\endgroup\$
    – Mr. Xcoder
    Oct 1, 2017 at 20:47
  • \$\begingroup\$ @Mr.Xcoder You can save a few bytes by optimizing indentation. \$\endgroup\$ Oct 2, 2017 at 22:05
  • \$\begingroup\$ Is the variable n used at all in your code? \$\endgroup\$
    – user9206
    Oct 21, 2017 at 20:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.