{"id":367476,"date":"2024-05-21T03:21:45","date_gmt":"2024-05-21T03:21:45","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=367476"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=367476","title":{"rendered":"<span>Python \u0434\u043b\u044f gambling&#8217;a. \u0427\u0430\u0441\u0442\u044c 1 \u2014 \u0421\u0431\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h3>\u041f\u0440\u043e\u043b\u043e\u0433<\/h3>\n<p>Hello, ladies and gentlemen!  <\/p>\n<p>\u0420\u0435\u0448\u0438\u043b \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0443\u043f\u0440\u0430\u0436\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u043f\u0443\u0431\u043b\u0438\u0446\u0438\u0441\u0442\u0438\u043a\u0435, \u0442\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u043f\u0435\u0440\u0432\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e. \u0422\u0430\u043a \u0447\u0442\u043e \u043d\u0435 \u0441\u0443\u0434\u0438\u0442\u0435 \u0441\u0442\u0440\u043e\u0433\u043e.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u043b\u044c\u0432\u0438\u043d\u0443\u044e \u0434\u043e\u043b\u044e \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u044f \u0442\u0440\u0430\u0442\u0438\u043b \u043d\u0430 \u043f\u043e\u0438\u0441\u043a\u0438 \u0440\u0430\u0431\u043e\u0442\u044b\/\u0441\u0442\u0430\u0436\u0438\u0440\u043e\u0432\u043a\u0438 \u0442\u0435\u0441\u0442\u0435\u0440\u043e\u0432\u0449\u0438\u043a\u043e\u043c.  \u0414\u0435\u043b\u043e \u044d\u0442\u043e \u043a\u0430\u043a \u0432\u044b\u044f\u0441\u043d\u0438\u043b\u043e\u0441\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0443\u0442\u043e\u043c\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0438 \u043d\u0435\u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u043d\u043e\u0435, \u043a \u0442\u043e\u043c\u0443 \u0436\u0435 \u0437\u0430 \u043f\u0440\u0430\u0437\u0434\u043d\u044b\u043c \u0432\u0440\u0435\u043c\u044f\u043f\u0440\u0435\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0448\u044c \u043f\u043e\u0442\u0438\u0445\u043e\u043d\u044c\u043a\u0443 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c \u0431\u0430\u0437\u0443, \u0442\u0430\u043a \u0447\u0442\u043e \u0440\u0435\u0448\u0438\u043b \u0441 \u044d\u0442\u0438\u043c \u0434\u0435\u043b\u043e\u043c \u043f\u0440\u0438\u0442\u043e\u0440\u043c\u043e\u0437\u0438\u0442\u044c, \u0441\u043b\u0435\u0433\u043a\u0430 \u0440\u0430\u0437\u0432\u0435\u044f\u0442\u044c\u0441\u044f \u0438 \u043a\u043e\u0435-\u0447\u0442\u043e \u043f\u043e\u0432\u0441\u043f\u043e\u043c\u0438\u043d\u0430\u0442\u044c. <\/p>\n<p>\u041f\u043e\u043d\u044f\u0442\u0438\u0435 &#171;\u0431\u0430\u0437\u0430&#187;, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0440\u0430\u0441\u0442\u044f\u0436\u0438\u043c\u043e\u0435. \u0414\u043b\u044f \u0441\u0435\u0431\u044f \u044f \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u0437\u044f\u043b Python \u0438 SQL.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0440\u0435\u0447\u044c \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u0439\u0434\u0435\u0442 \u043e \u0441\u0431\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u043e \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0435\/\u0441\u043a\u0440\u0430\u043f\u043f\u0438\u043d\u0433\u0435 (\u043a\u0442\u043e \u043a\u0430\u043a \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u0435\u0442), \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u043c \u0430\u043d\u0430\u043b\u0438\u0437\u0435 \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 Python \u0431\u0443\u0434\u0443\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044b \u0442\u0430\u043a\u0438\u0435 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043a\u0430\u043a Playwright, Requests, bs4, \u0438 psycopg2(\u043d\u0430\u0434\u043e \u0436\u0435 \u043a\u0443\u0434\u0430-\u0442\u043e \u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c).<\/p>\n<p>\u042d\u0442\u043e\u0442 \u043d\u0435\u0437\u0430\u043c\u044b\u0441\u043b\u043e\u0432\u0430\u0442\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u043d\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043f\u043e\u0440\u0442\u0438\u0432\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 \u043f\u043e \u0431\u0430\u0441\u043a\u0435\u0442\u0431\u043e\u043b\u0443, \u0430 \u0442\u043e\u0447\u043d\u0435\u0435 \u0442\u0440\u0435\u0445 \u0442\u0430\u0431\u043b\u0438\u0446 \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u043e \u0432\u0441\u044f\u043a\u043e\u043c\u0443 \u043f\u043e\u0438\u0433\u0440\u0430\u0442\u044c\u0441\u044f.<\/p>\n<h3>\u041d\u0430\u0447\u0430\u043b\u043e<\/h3>\n<p>\u041c\u043d\u0435 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f UI \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u0441\u044f \u0441\u0435\u0440\u0432\u0438\u0441 flashscore.com. \u041e\u043d\u0438 \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u043f\u0430\u0440\u044f\u0442\u0441\u044f \u043f\u043e \u043f\u043e\u0432\u043e\u0434\u0443 \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043a\u043e\u0440\u044f\u0447\u0438\u0442\u044c\u0441\u044f \u0441\u043e \u0432\u0441\u044f\u043a\u0438\u043c\u0438 selenium-stealth \u0438 fakeuseragent-\u0430\u043c\u0438. \u0423 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u043e\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0431\u0430\u0441\u043a\u0435\u0442\u0431\u043e\u043b\u0430 &#8212; basketball24.com.<\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u044b \u0434\u0435\u043b\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f:<\/p>\n<ul>\n<li>\n<p>Python<\/p>\n<\/li>\n<li>\n<p>Playwright<\/p>\n<\/li>\n<li>\n<p>requests + bs4 (\u0434\u043b\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043c\u043e\u0436\u043d\u043e \u0432 \u043e\u0431\u0449\u0435\u043c-\u0442\u043e \u0431\u0435\u0437 \u043d\u0438\u0445)<\/p>\n<\/li>\n<li>\n<p>psycopg2 (\u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e postgresql)<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u043e\u0434\u043d\u044b\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0438\u0437 \u0441\u0435\u0440\u0438\u0438 json\/os\/sys \u0438 \u0442.\u0434.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0431\u0443\u0434\u0443 \u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0440\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0442\u0430\u043a\u043e\u0433\u043e \u0440\u043e\u0434\u0430:<\/p>\n<p>1.championships<strong>:<\/strong><\/p>\n<ul>\n<li>\n<p>id (\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043b\u0438\u0433\u0438)<\/p>\n<\/li>\n<li>\n<p>country (\u0441\u0442\u0440\u0430\u043d\u0430 \u043b\u0438\u0433\u0438)<\/p>\n<\/li>\n<li>\n<p>gender (\u043c\u0443\u0436\u0441\u043a\u043e\u0439 \u0438 \u0436\u0435\u043d\u0441\u043a\u0438\u0439)<\/p>\n<\/li>\n<li>\n<p>league (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043b\u0438\u0433\u0438)<\/p>\n<\/li>\n<li>\n<p>link (\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0430\u0440\u0445\u0438\u0432 \u0441\u043e \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u043e\u0439)<\/p>\n<\/li>\n<\/ul>\n<p>2.matches<strong>:<\/strong><\/p>\n<ul>\n<li>\n<p>match_id (\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043c\u0430\u0442\u0447\u0430)<\/p>\n<\/li>\n<li>\n<p>league_id (id \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b championships)<\/p>\n<\/li>\n<li>\n<p>match_date (\u0434\u0430\u0442\u0430 \u0432\u0441\u0442\u0440\u0435\u0447\u0438)<\/p>\n<\/li>\n<li>\n<p>start_time (\u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u0441\u0442\u0440\u0435\u0447\u0438, \u0443 \u043c\u0435\u043d\u044f UTC +01:00)<\/p>\n<\/li>\n<li>\n<p>team_home (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b)<\/p>\n<\/li>\n<li>\n<p>team_away (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043d\u0430 \u0432\u044b\u0435\u0437\u0434\u0435)<\/p>\n<\/li>\n<li>\n<p>league_name (\u0442\u043e \u0436\u0435 \u0447\u0442\u043e \u0438 league \u0438\u0437 championships)<\/p>\n<\/li>\n<li>\n<p>stage (\u044d\u0442\u0430\u043f \u0442\u0443\u0440\u043d\u0438\u0440\u0430)<\/p>\n<\/li>\n<li>\n<p>home_score (\u043e\u0447\u043a\u0438 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043e\u0432\u0435\u0440\u0442\u0430\u0439\u043c)<\/p>\n<\/li>\n<li>\n<p>away_score (\u043e\u0447\u043a\u0438 \u0433\u043e\u0441\u0442\u0435\u0432\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043e\u0432\u0435\u0440\u0442\u0430\u0439\u043c)<\/p>\n<\/li>\n<li>\n<p>home_score_ft (\u043e\u0447\u043a\u0438 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f)<\/p>\n<\/li>\n<li>\n<p>away_score_ft (\u043e\u0447\u043a\u0438 \u0433\u043e\u0441\u0442\u0435\u0432\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f)<\/p>\n<\/li>\n<li>\n<p>total_ft (\u043e\u0447\u043a\u0438 \u043e\u0431\u0435\u0438\u0445 \u043a\u043e\u043c\u0430\u043d\u0434 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f)<\/p>\n<\/li>\n<\/ul>\n<p>3.details<strong>:<\/strong><\/p>\n<ul>\n<li>\n<p>match_id (\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043c\u0430\u0442\u0447\u0430, \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b matches)<\/p>\n<\/li>\n<li>\n<p>home_q1 &#8230; away_ot (10 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432 \u0441 \u043d\u0430\u0431\u0440\u0430\u043d\u043d\u044b\u043c\u0438 \u043e\u0447\u043a\u0430\u043c\u0438 \u043a\u0430\u0436\u0434\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432 \u043e\u0432\u0435\u0440\u0442\u0430\u0439\u043c\u0435, \u0435\u0441\u043b\u0438 \u043e\u043d \u0431\u044b\u043b)<\/p>\n<\/li>\n<li>\n<p>home_win (\u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043d\u0430 \u043f\u043e\u0431\u0435\u0434\u0443 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b)<\/p>\n<\/li>\n<li>\n<p>away_win (\u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043d\u0430 \u043f\u043e\u0431\u0435\u0434\u0443 \u0433\u043e\u0441\u0442\u0435\u0432\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b)<\/p>\n<\/li>\n<li>\n<p>total (\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u0442\u043e\u0442\u0430\u043b\u0430 \u043d\u0430 \u0440\u0430\u0432\u043d\u044b\u0435 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u044b*)<\/p>\n<\/li>\n<li>\n<p>handicap (\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u0440\u0435\u0434\u043d\u0435\u0439 \u0444\u043e\u0440\u044b\/\u0433\u0430\u043d\u0434\u0438\u043a\u0430\u043f\u0430 \u043d\u0430 \u0440\u0430\u0432\u043d\u044b\u0435 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u044b* \u043f\u043e \u0438\u0442\u043e\u0433\u0443 \u043c\u0430\u0442\u0447\u0430)<\/p>\n<\/li>\n<li>\n<p>hc_q1 (\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u0440\u0435\u0434\u043d\u0435\u0439 \u0444\u043e\u0440\u044b\/\u0433\u0430\u043d\u0434\u0438\u043a\u0430\u043f\u0430 \u043d\u0430 \u0440\u0430\u0432\u043d\u044b\u0435 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u044b* \u043f\u043e \u0438\u0442\u043e\u0433\u0443 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u0438)<\/p>\n<p><em>*\u0440\u0430\u0432\u043d\u044b\u0435 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u044e \u0447\u0442\u043e \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0432\u0432\u0438\u0434\u0443 &#8212; \u043d\u0430 \u043c\u0430\u0442\u0447 \u0434\u0430\u044e\u0442 \u0441\u0440\u0435\u0434\u043d\u0438\u0439 \u0442\u043e\u0442\u0430\u043b 165.5 , \u0442\u043e \u0435\u0441\u0442\u044c \u043d\u0430 \u0422\u043e\u0442\u0430\u043b \u041c\u0435\u043d\u044c\u0448\u0435 165.5(\u0422\u041c) \u0434\u0430\u044e\u0442 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 1.87 \u0438 \u043d\u0430 \u0422\u043e\u0442\u0430\u043b \u0411\u043e\u043b\u044c\u0448\u0435 165.5(\u0422\u0411) &#8212; \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 1.87, \u0442\u043e \u0436\u0435 \u0438 \u0441 \u0444\u043e\u0440\u0430\u043c\u0438, \u0438\u043d\u043e\u0433\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b &#8212; 1.86 \u0438 1.88, 1.89 \u0438 1.85 , 1.9 \u0438 1.87 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e(\u0437\u0432\u0438\u0441\u044f\u0442 \u043e\u0442 \u043c\u0430\u0440\u0436\u0438 \u0431\u0443\u043a\u043c\u0435\u043a\u0435\u0440\u0430 \u0438 \u0432\u0435\u043b\u0438\u0447\u0438\u043d\u044b \u0440\u044b\u043d\u043a\u0430, \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u0438 \u0431\u043b\u0438\u0437\u043a\u0438 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u043d\u0430 \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u043b\u043e\u0436\u043d\u044b\u0435 \u0438\u0441\u0445\u043e\u0434\u044b).<\/em><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre><code>championships   id | country | gender |  league   |                      link ----+---------+--------+-----------+------------------------------------------------<\/code><\/pre>\n<pre><code>matches   match_id | league_id | match_date | start_time | team_home | team_away | league_name | stage | home_score | away_score | home_score_ft | away_score_ft | total_ft ----------+-----------+------------+------------+-----------+-----------+-------------+-------+------------+------------+---------------+---------------+----------<\/code><\/pre>\n<pre><code>details   match_id | home_q1 | away_q1 | home_q2 | away_q2 | home_q3 | away_q3 | home_q4 | away_q4 | home_ot | away_ot | home_win | away_win | total | handicap | hc_q1 ----------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+----------+----------+-------+----------+-------<\/code><\/pre>\n<h3>\u041d\u0430\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u21161<\/h3>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043f\u0435\u0440\u0432\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b &#8212; championships. <\/p>\n<p>\u041d\u0430 basketball24.com \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\u043e\u0432 \u0438\u0437 \u0432\u0441\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0441\u0442\u0440\u0430\u043d, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435  <\/p>\n<figure class=\"float\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5bc\/9b2\/1d1\/5bc9b21d1e14655c5ceda19134232d46.png\" alt=\"\u041d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0424\u0440\u0430\u043d\u0446\u0438\u0438 \u044f \u0432\u043e\u0437\u044c\u043c\u0443 3 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\u0430 - \u041f\u0435\u0432\u0440\u0443\u044e \u0438 \u0412\u0442\u043e\u0440\u0443\u044e \u043b\u0438\u0433\u0443 \u0443 \u043c\u0443\u0436\u0447\u0438\u043d (LNB \u0438 Pro B), \u0438 \u041f\u0435\u0440\u0432\u0443\u044e \u043b\u0438\u0433\u0443 \u0443 \u0436\u0435\u043d\u0449\u0438\u043d (LFB Women)\" title=\"\u041d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0424\u0440\u0430\u043d\u0446\u0438\u0438 \u044f \u0432\u043e\u0437\u044c\u043c\u0443 3 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\u0430 - \u041f\u0435\u0432\u0440\u0443\u044e \u0438 \u0412\u0442\u043e\u0440\u0443\u044e \u043b\u0438\u0433\u0443 \u0443 \u043c\u0443\u0436\u0447\u0438\u043d (LNB \u0438 Pro B), \u0438 \u041f\u0435\u0440\u0432\u0443\u044e \u043b\u0438\u0433\u0443 \u0443 \u0436\u0435\u043d\u0449\u0438\u043d (LFB Women)\" width=\"320\" height=\"492\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5bc\/9b2\/1d1\/5bc9b21d1e14655c5ceda19134232d46.png\"\/><\/p>\n<div><figcaption>\u041d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0424\u0440\u0430\u043d\u0446\u0438\u0438 \u044f \u0432\u043e\u0437\u044c\u043c\u0443 3 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\u0430 &#8212; \u041f\u0435\u0432\u0440\u0443\u044e \u0438 \u0412\u0442\u043e\u0440\u0443\u044e \u043b\u0438\u0433\u0443 \u0443 \u043c\u0443\u0436\u0447\u0438\u043d (LNB \u0438 Pro B), \u0438 \u041f\u0435\u0440\u0432\u0443\u044e \u043b\u0438\u0433\u0443 \u0443 \u0436\u0435\u043d\u0449\u0438\u043d (LFB Women)<\/figcaption><\/div>\n<\/figure>\n<p><\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u044f \u0443\u0432\u043b\u0435\u043a\u0441\u044f \u0438 \u043d\u0430\u0441\u043e\u0431\u0438\u0440\u0430\u043b 101 \u043c\u0443\u0436\u0441\u043a\u043e\u0439 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442 \u0438 48 \u0436\u0435\u043d\u0441\u043a\u0438\u0445. \u042d\u0442\u043e \u043f\u0435\u0440\u0432\u044b\u0435 \u0438 \u0432\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043b\u0438\u0433\u0438 \u0438 \u0435\u0432\u0440\u043e\u043f\u0435\u0439\u0441\u043a\u0438\u0435 \u043c\u0435\u0436\u043a\u043b\u0443\u0431\u043d\u044b\u0435 \u043f\u0435\u0440\u0432\u0435\u043d\u0441\u0442\u0432\u0430. \u042f \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043b \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442 \u0438 \u043f\u043e\u043b\u043e\u0436\u0438\u043b \u0432 \u0432\u0438\u0434\u0435 \u0434\u0432\u0443\u0445 \u0441\u043f\u0438\u0441\u043a\u043e\u0432: \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043c\u0443\u0436\u0441\u043a\u0438\u0445 \u0438 \u0436\u0435\u043d\u0441\u043a\u0438\u0445  <\/p>\n<pre><code>#bb_links.py  links_men = [     'https:\/\/www.basketball24.com\/albania\/superliga\/#\/QyhUb9xl\/table\/overall',     'https:\/\/www.basketball24.com\/argentina\/liga-a\/#\/KbRL3M3T\/table\/overall',     'https:\/\/www.basketball24.com\/australia\/nbl\/#\/YZEnCJej\/table\/overall',     ... ]  links_women = [     'https:\/\/www.basketball24.com\/argentina\/liga-femenina-women\/#\/UgCeKslA\/draw',     'https:\/\/www.basketball24.com\/australia\/wnbl-women\/#\/IBGTDowC\/table\/overall',     'https:\/\/www.basketball24.com\/austria\/superliga-women\/#\/Sx8xPi88\/table\/overall',     ... ]<\/code><\/pre>\n<p>\u0424\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0441 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u0434\u043e\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u0432\u0441\u044f\u043a\u0443\u044e \u0435\u0440\u0443\u0434\u043d\u0443 (\u043f\u043e \u0442\u0438\u043f\u0443 \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u043e\u0432, \u0432\u0440\u043e\u0434\u0435 &#171;#\/Sx8xPi88\/table\/overall&#187;) &#8212; \u043d\u0438\u0447\u0435\u0433\u043e \u0441\u0442\u0440\u0430\u0448\u043d\u043e\u0433\u043e, \u043f\u043e\u0442\u043e\u043c \u044d\u0442\u043e \u0434\u0435\u043b\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u043c.<\/p>\n<p>\u041c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u043f\u0435\u0440\u0432\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b championships:<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\u0442\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u0442\u044c) \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<br \/>.<br \/> \u251c\u2500\u2500 <a href=\"http:\/\/championships.py\" rel=\"noopener noreferrer nofollow\">championships.py<\/a><br \/> \u251c\u2500\u2500 link_collector.py<br \/> \u251c\u2500\u2500 main_run.py<br \/> \u251c\u2500\u2500 failed_run.py<br \/> \u251c\u2500\u2500 details<br \/> \u2502   \u251c\u2500\u2500 all_champs.json<br \/> \u2502   \u251c\u2500\u2500 bb_links.py<br \/> \u2502   \u2514\u2500\u2500 main_selectors.py<br \/> \u2502   \u251c\u2500\u2500 txt_links<br \/> \u2502   \u2502   \u2514\u2500\u2500 austria-superliga.txt<br \/> \u2502   \u2502   \u2514\u2500\u2500 failed<br \/> \u2502   \u2502       \u2514\u2500\u2500 japan-b-league.txt<br \/> \u251c\u2500\u2500 sport_handlers<br \/> \u2502   \u251c\u2500\u2500 basketball_handler.py<br \/> \u2502   \u2514\u2500\u2500 main_handler.py<br \/> \u2514\u2500\u2500 tests<br \/>      \u251c\u2500\u2500 test_leagues_actuality.py<br \/>      \u2514\u2500\u2500 test_slector_validity.py<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043a\u043e\u043c\u0443-\u0442\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0432\u0441\u044e \u0440\u0435\u043f\u0443 &#8212; <a href=\"https:\/\/github.com\/DenisLet\/SportDB\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>.<\/p>\n<pre><code class=\"python\">#championships.py  import os import json import psycopg2 from .details.bb_links import links_men, links_women  '''    Class create json and sql table with basketball     championships(and link for them to basketball24.com      choosen by yourself manually before '''   class Championships:      def __init__(self, sport=None):         self.all_leagues = {}         self.sport = sport         print(self.sport)      def add_league(self, data, gender):         for l in data:             country = l.split('\/')[3].replace('-', ' ').title()             league = l.split('\/')[4].replace('-', ' ').upper()             link = 'https:\/' + '\/'.join(l.split('\/')[1:5])              if country not in self.all_leagues:                 self.all_leagues[country] = {'Men': {}, 'Women': {}}              if league not in self.all_leagues[country][gender]:                 self.all_leagues[country][gender][league] = link      def process_data(self, data_men, data_women):         self.add_league(data_men, 'Men')         self.add_league(data_women, 'Women')      def save_to_json(self, filename='all_champs.json'):         folder_path = 'details'         file_path = os.path.join(folder_path, filename)         json_data = json.dumps(self.all_leagues, indent=4)         with open(file_path, 'w') as file:             file.write(json_data)       def connect_to_db(self, dbname):         return psycopg2.connect(             host=\"127.0.0.1\",             user=\"postgres\",             password=\"123456er\",             port=\"5432\",             dbname=dbname         )      def create_postgresql_db(self, dbname):         conn = self.connect_to_db(dbname)         cur = conn.cursor()          # \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 - \u0435\u0441\u0442\u044c \u0431\u0430\u0437\u0430 \u0438\u043b\u0438 \u043d\u0435\u0442         cur.execute(f\"SELECT 1 FROM pg_catalog.pg_database WHERE datname = '{dbname}'\")         database_exists = cur.fetchone()          # \u0415\u0441\u043b\u0438 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0435\u0442, \u0441\u043e\u0437\u0434\u0430\u044e \u043d\u043e\u0432\u0443\u044e         if not database_exists:             cur.execute(f\"CREATE DATABASE {dbname}\")             print(f\"Database '{dbname}' created successfully\")          conn.close()          # \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e\u0441\u044c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0439 \u0438\u043b\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0431\u0430\u0437\u0435         conn = self.connect_to_db(dbname)         cur = conn.cursor()          # \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 \u0431\u0430\u0437\u0435         cur.execute(\"SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'championships')\")         table_exists = cur.fetchone()[0]          # \u0415\u0441\u043b\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043d\u0435\u0442, \u0441\u043e\u0437\u0434\u0430\u044e \u043d\u043e\u0432\u0443\u044e         if not table_exists:             create_table_query = '''                 CREATE TABLE championships (                     id SERIAL PRIMARY KEY,                     country VARCHAR(100),                     gender VARCHAR(10),                     league VARCHAR(100),                     link VARCHAR(255),                     CONSTRAINT unique_country_gender_league UNIQUE (country, gender, league)                 )             '''             cur.execute(create_table_query)             conn.commit()             print(\"Table created successfully\")           for country, genders in self.all_leagues.items():             for gender, leagues in genders.items():                 for league, link in leagues.items():                     insert_query = f'''                         INSERT INTO championships (country, gender, league, link)                          VALUES ('{country}', '{gender}', '{league}', '{link}')                         ON CONFLICT (country, gender, league) DO NOTHING                     '''                     cur.execute(insert_query)                     conn.commit()          conn.close()  championships = Championships() championships.process_data(links_men, links_women) championships.save_to_json() championships.create_postgresql_db(dbname=\"sportdb\")<\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043c\u043e\u0434\u0443\u043b\u0435 \u043e\u0434\u0438\u043d \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u0437\u0432\u0430\u043d \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432\u0441\u0435 \u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0440\u0443\u043a\u0430\u043c\u0438 \u0441\u0441\u044b\u043b\u043a\u0438, \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0438\u0445 \u043f\u043e \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\u0430\u043c, \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 JSON (\u043e\u043d \u043f\u0440\u0438\u0433\u043e\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0438\u043d\u043e\u0433\u0434\u0430 \u043f\u043e\u0434\u0435\u0440\u0433\u0430\u0442\u044c \u043b\u0438\u043d\u043a\u0438 \u0432\u0440\u0443\u0447\u043d\u0443\u044e) \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c (\u0435\u0441\u043b\u0438 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0437\u0430\u0440\u0430\u043d\u0435\u0435) \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 sportdb, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 championships (\u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0437\u0430\u043a\u043e\u043b\u0445\u043e\u0437\u0438\u0442\u044c \u0442\u0440\u043e\u0435\u043a\u0440\u0430\u0442\u043d\u044b\u043c for, \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439 \u043c\u0430\u043b\u043e &#8212; \u0442\u0430\u043a \u0447\u0442\u043e \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e).  <\/p>\n<p>\u0412\u044b\u0448\u043b\u043e \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/272\/471\/530\/2724715304762e959810755fcb60b17e.png\" alt=\"\u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u043f\u043e 35 \u0441\u0442\u0440\u043e\u043a\u0443 - champioships\" title=\"\u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u043f\u043e 35 \u0441\u0442\u0440\u043e\u043a\u0443 - champioships\" width=\"1131\" height=\"690\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/272\/471\/530\/2724715304762e959810755fcb60b17e.png\"\/><\/p>\n<div><figcaption>\u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u043f\u043e 35 \u0441\u0442\u0440\u043e\u043a\u0443 &#8212; champioships<\/figcaption><\/div>\n<\/figure>\n<pre><code class=\"json\">{     \"Albania\": {         \"Men\": {             \"SUPERLIGA\": \"https:\/\/www.basketball24.com\/albania\/superliga\"         },         \"Women\": {}     },     \"Argentina\": {         \"Men\": {             \"LIGA A\": \"https:\/\/www.basketball24.com\/argentina\/liga-a\"         },         \"Women\": {              \"LIGA FEMENINA WOMEN\": \"https:\/\/www.basketball24.com\/argentina\/liga-femenina-women\"         }     },     \"Australia\": {         \"Men\": {             \"NBL\": \"https:\/\/www.basketball24.com\/australia\/nbl\"         },         \"Women\": {             \"WNBL WOMEN\": \"https:\/\/www.basketball24.com\/australia\/wnbl-women\"         } ... }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0434 \u0432 \u0442\u0435\u043e\u0440\u0438\u0438 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439, \u0430 \u0441\u0441\u044b\u043b\u043a\u0438 \u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\u043e\u0432 \u0438\u043c\u0435\u044e\u0442 \u0441\u0432\u043e\u0439\u0441\u0432\u043e \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u043e \u0440\u0430\u0437\u043d\u044b\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c(\u043d\u0430\u043f\u0440\u043c\u0435\u0440, \u0441\u043c\u0435\u043d\u0438\u043b\u0441\u044f \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0441\u043f\u043e\u043d\u0441\u043e\u0440), \u043d\u0443\u0436\u043d\u043e \u0438\u043d\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0438.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/4a4\/9c2\/8a4\/4a49c28a4e6004e4cdd38fd31476cbb2.png\" alt=\"\u0432\u043e\u0442 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442 \u0429\u0432\u0435\u0446\u0438\u0438 \u043f\u043e\u043c\u0435\u043d\u044f\u043b \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0432 \u0441\u0435\u0437\u043e\u043d\u0435 2018\/2019\" title=\"\u0432\u043e\u0442 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442 \u0429\u0432\u0435\u0446\u0438\u0438 \u043f\u043e\u043c\u0435\u043d\u044f\u043b \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0432 \u0441\u0435\u0437\u043e\u043d\u0435 2018\/2019\" width=\"678\" height=\"599\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4a4\/9c2\/8a4\/4a49c28a4e6004e4cdd38fd31476cbb2.png\"\/><\/p>\n<div><figcaption>\u0432\u043e\u0442 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442 \u0429\u0432\u0435\u0446\u0438\u0438 \u043f\u043e\u043c\u0435\u043d\u044f\u043b \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0432 \u0441\u0435\u0437\u043e\u043d\u0435 2018\/2019<\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u043b\u044f \u0442\u0430\u043a\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0442\u0435\u0441\u0442\u0438\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e pytest \u0438 requests+bs4. \u0418 \u0437\u0430\u0440\u0430\u044f\u0434\u0438\u0442\u044c \u044d\u0442\u043e \u0434\u0435\u043b\u043e \u043d\u0430 github actions, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0440\u0430\u0437 \u0432 \u043d\u0435\u0434\u0435\u043b\u044e \u0441\u0443\u0442\u0440\u0430 \u043f\u043e \u043f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a\u0430\u043c. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u043d\u043e\u0443\u0442\u0431\u0443\u043a\u0435 \u0441 actions &#8212; \u0434\u0435\u043b\u043e \u0445\u043b\u043e\u043f\u043e\u0442\u043d\u043e\u0435, \u043e\u0444\u043e\u0440\u043c\u0438\u043b \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435, \u0447\u0442\u043e \u0445\u043e\u0447\u0443 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c.  <\/p>\n<pre><code>#bb_to_test.py  leagues = [ ('SUPERLIGA', 'https:\/\/www.basketball24.com\/albania\/superliga'),  ('LIGA A', 'https:\/\/www.basketball24.com\/argentina\/liga-a'),  ('LIGA FEMENINA WOMEN', 'https:\/\/www.basketball24.com\/argentina\/liga-femenina-women'), ... ]<\/code><\/pre>\n<pre><code class=\"python\">#test_leagues_actuality.py  import requests from bs4 import BeautifulSoup import pytest from details import bb_to_test  # \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u043e\u043a, \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u044f \u0441\u0438\u043c\u0432\u043e\u043b\u044b, \u043a\u0440\u043e\u043c\u0435 \u0431\u0443\u043a\u0432 \u0438 \u0446\u0438\u0444\u0440 def clean_string(s):     return ''.join(filter(str.isalnum, s)).lower()  # \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0447\u0442\u043e \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043b\u0438\u0433\u0443 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u0430 \u0438 \u043d\u0430\u0437\u0432\u0430\u0435\u0438\u0435 \u043b\u0438\u0433\u0438 \u043d\u0435 \u043f\u043e\u043c\u0435\u043d\u044f\u043b\u0438 @pytest.mark.parametrize(\"league, link\", bb_to_test.leagues, ids=lambda item: item) def test_links_match(league, link):     response = requests.get(link)     assert response.status_code == 200      soup = BeautifulSoup(response.text, 'html.parser')     element = soup.find(class_='heading__name').text.strip().lower()      assert clean_string(element) == clean_string(league)<\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u044e, \u0447\u0442\u043e \u043e\u0442\u0432\u0435\u0442 \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u0439 (200), \u0437\u043d\u0430\u0447\u0438\u0442, \u0441\u0441\u044b\u043b\u043a\u0430 \u0436\u0438\u0432\u0430, \u0438 \u043f\u044b\u0442\u0430\u044e\u0441\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442 \u043d\u0435 \u043f\u043e\u043c\u0435\u043d\u044f\u043b\u0441\u044f. \u0421\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u044e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043b\u0438\u0433\u0438 \u0438\u0437 \u0441\u0441\u044b\u043b\u043a\u0438 \u0438 \u0435\u0451 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 (\u0434\u0430, \u0442\u0430\u043a\u043e\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0447\u0442\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f).<\/p>\n<p>\u0428\u043b\u0435\u043f\u043d\u0443\u0442, \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430, \u0443 \u0441\u0435\u0431\u044f \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435, \u0440\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, &#8212; \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u043a\u0430\u043a \u0442\u0430\u043c \u0434\u0435\u043b\u0430:<\/p>\n<pre><code>pytest .\\test_leagues_actuality.py -v .... test_leagues_actuality.py::test_links_match[SUPERLIGA-https:\/\/www.basketball24.com\/albania\/superliga] PASSED                                                                                                                 [  0%] test_leagues_actuality.py::test_links_match[LIGA A-https:\/\/www.basketball24.com\/argentina\/liga-a] PASSED                                                                                                                     [  1%] test_leagues_actuality.py::test_links_match[LIGA FEMENINA WOMEN-https:\/\/www.basketball24.com\/argentina\/liga-femenina-women] PASSED          ...<\/code><\/pre>\n<pre><code class=\"yaml\">name: Run Tests  on:   push:     branches:       - master     schedule:     - cron: '0 7 * * 1'  #\u0437\u0430\u043f\u0443\u0441\u043a \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a \u0432 7 \u0443\u0442\u0440\u0430  jobs:   test:     runs-on: windows-latest  #\u043d\u0430 \u0443\u0431\u0443\u043d\u0442\u0435 \u0442\u0435\u0441\u0442\u044b \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u044b\u0441\u0442\u0440\u0435\u0435      steps:     - name: Checkout repository       uses: actions\/checkout@v2      - name: Set up Python       uses: actions\/setup-python@v2       with:         python-version: 3.10.7      - name: Install dependencies       run: |         python -m pip install --upgrade pip         pip install -r requirements.txt      - name: Set up Playwright       run: |         python -m playwright install      - name: Run tests       run: pytest <\/code><\/pre>\n<p>\u0412 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0442\u0435\u0441\u0442 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u043e\u0432 (\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043d\u0443\u0436\u043d\u044b \u043f\u0440\u0438 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0435), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0442\u0443\u0442 \u0432 YAML-\u0444\u0430\u0439\u043b\u0435 \u0435\u0441\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0430 python -m playwright install.  <\/p>\n<h2>Playwright<\/h2>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0430\u043c \u0443\u0436\u0435 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u044c \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u043c\u0438 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u0421\u0430\u043c\u044b\u0439 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e &#8212; Selenium, \u044d\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u043b\u0438\u0447\u043d\u0430\u044f \u0448\u0442\u0443\u043a\u0430, \u043d\u043e \u043c\u0435\u043d\u044f \u0432\u043e\u0440\u043e\u0442\u0438\u0442 \u043e\u0442 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f webdriver-\u0430, \u0430 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0435\u0433\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u043e\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 Ubuntu, \u044f \u0442\u0430\u043a \u0438 \u043d\u0435 \u043f\u043e\u0441\u0442\u0438\u0433, \u0447\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0431\u044b\u0441\u0442\u0440\u043e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043d\u0435 \u0431\u043b\u0438\u0436\u0435 Playwright, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0441\u0432\u043e\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440. \u0412 \u0438\u0434\u0435\u0430\u043b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c TypeScript \u0441 \u044d\u0442\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439, \u043d\u043e \u043c\u043d\u0435 \u043f\u0440\u043e\u0449\u0435 Python. \u042f \u0431\u0443\u0434\u0443 \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u0432 \u0441\u043b\u0435\u0433\u043a\u0430 \u043c\u0430\u0440\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435, \u0431\u0435\u0437 \u0438\u0437\u044b\u0441\u043a\u043e\u0432, \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0439, \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0439 \u0442\u0438\u043f\u043e\u0432 \u0438 \u0442.\u0434., \u0437\u0430 \u044d\u0442\u043e &#8212; \u0441\u043e\u0440\u0440\u0438.  <\/p>\n<p>\u041f\u043e \u0445\u043e\u0440\u043e\u0448\u0435\u043c\u0443, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Playwright \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435, \u044d\u0442\u043e \u0443\u0441\u043a\u043e\u0440\u044f\u0435\u0442 \u0438 \u043f\u0430\u0440\u0441\u0438\u043d\u0433, \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443, \u043d\u043e \u0443 \u043c\u0435\u043d\u044f \u0434\u0440\u0435\u0432\u043d\u0438\u0439 Lenovo B590 \u0441 4 \u0413\u0411 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043a\u0438 \u0438 \u043e\u0447\u0435\u043d\u044c \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0435\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u043b\u0438\u0448\u0435\u043d\u043e \u043b\u043e\u0433\u0438\u043a\u0438, \u0438 \u0432\u0441\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u0432 sync.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043c \u0441\u043d\u043e\u0432\u0430 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0438, \u043d\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\u0430 \u043f\u043e \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0441\u0435\u0437\u043e\u043d\u0443. \u042f \u0432\u0437\u044f\u043b \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0441\u0435\u0437\u043e\u043d \u0438 \u0447\u0435\u0442\u044b\u0440\u0435 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445.<\/p>\n<pre><code class=\"python\">#link_collector.py  import requests import os from bs4 import BeautifulSoup from playwright.sync_api import sync_playwright, TimeoutError from details.main_selectors import Selectors import sys  class SeasonsCollector:     def __init__(self, link):         self.champ = link         self.all_links = None         self.seasons = 5      def get_links(self):         archive_link = f'{self.champ}\/archive'         response = requests.get(archive_link)         soup = BeautifulSoup(response.text, 'html.parser')         pre_link = f\"{'\/'.join(self.champ.split('\/')[:-1])}\/\"         self.all_links = [pre_link + i.get('href').split('\/')[2] for cnt, i in                           enumerate(soup.select('.archive__season a'))                           if cnt &lt; self.seasons]         return self.all_links   class SeasonsHandler:     def __init__(self, links):         self.links = links         self.browser = sync_playwright().start().chromium.launch(headless=False)         self.context = self.browser.new_context()         self.pages = []      def open_pages(self):         for link in self.links:             page = self.context.new_page()             page.goto(link)             self.pages.append(page)             print(self.pages)      def click_to_bottom(self):         for page in self.pages:             while True:                 try:                     elements = page.query_selector_all(Selectors.show_more)                     if len(elements) == 0:                         break                     elements[0].click()                     page.wait_for_load_state('networkidle', timeout=300000)                 except TimeoutError:                     continue                 import time                 time.sleep(1)      def get_links_to_matches(self, sport_selector):         all_links = []         for page in self.pages:             all_matches = page.query_selector_all(sport_selector)             for match in all_matches:                 match_id = match.get_attribute('id')                 href = '\/'.join(f'{page.url}'.split('\/')[:3]) + '\/match\/' + match_id[4:]                 all_links.append(href)             print(len(all_links))         return all_links      def close_all(self):         for page in self.pages:             page.close()         self.context.close()         self.browser.close()         print('browser has been closed')   def link_collerctor(url):     links_champ = SeasonsCollector(url).get_links()     handler = SeasonsHandler(links_champ)     handler.open_pages()     handler.click_to_bottom()     matches_links = handler.get_links_to_matches(Selectors.bb_all_matches)     handler.close_all()     file_name = '-'.join(url.split('\/')[-2:])     with open(f\"details\\\\txt_links\\\\{file_name}.txt\", \"w\") as file:         file.write(\"\\n\".join(matches_links))   if __name__ == \"__main__\":     if len(sys.argv) != 2:         print('Usage: python link_collector.py [url]')         sys.exit(1)     arg = sys.argv[1]     link_collerctor(arg)<\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043c\u043e\u0434\u0443\u043b\u0435 \u043a\u043b\u0430\u0441\u0441 SeasonsCollector \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 5 (self.seasons = 5) \u0441\u0435\u0437\u043e\u043d\u043e\u0432 &#8212; \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0438 4 \u043f\u0440\u043e\u0448\u043b\u044b\u0445. \u041a\u043b\u0430\u0441\u0441 SeasonsHandler \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043c\u0430\u0442\u0447 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u0435\u0437\u043e\u043d\u0435. \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043c\u0430\u0442\u0447\u0438 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0435\u0437\u043e\u043d\u0430 \u0441\u0440\u0430\u0437\u0443 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e, \u0430 \u043f\u043e\u0440\u0446\u0438\u043e\u043d\u043d\u043e, \u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043a\u043b\u0438\u043a\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 &#171;Show more matches&#187;, \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0439\u0442\u0438 \u0434\u043e \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0435\u0437\u043e\u043d\u0430.  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2fc\/eae\/cf6\/2fceaecf67ba67f58f2f473343c738ef.png\" alt=\"\" title=\"\" width=\"689\" height=\"667\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2fc\/eae\/cf6\/2fceaecf67ba67f58f2f473343c738ef.png\"\/><\/figure>\n<p>\u0412 \u043c\u043e\u0434\u0443\u043b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u044b, \u044f \u0438\u0445 \u043f\u043e\u0438\u0441\u043a\u0430\u043b \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0438 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0441\u043b\u043e\u0436\u0438\u043b \u0432 \u043c\u043e\u0434\u0443\u043b\u044c main_selectors.py<\/p>\n<pre><code class=\"python\">#main_selectors.py  class Selectors:     bb_all_matches = \"[id^='g_3']\"   #     scoreline = '.smh__template'     team_home = 'div.participant__participantName:nth-child(2)'     team_away = 'div.participant__participantName:nth-child(1)'     tournament = '.tournamentHeader__country'     date_and_time = '.duelParticipant__startTime'     final_score = '.detailScore__wrapper'     show_more = '.event__more.event__more--static'     fulltime_score = '.detailScore__fullTime'      class CustomIndexedList(list):       #Pardon my french         '''         TAKE CARE !!!         To ensure that quarters in basketball, periods in hockey, and halves in football and handball         correspond to their actual values rather than the standard indexing, an offset of 1 is applied.         '''         def __getitem__(self, index):             if 1 &lt;= index &lt;= 5:                 # Adjust the index to start from 1 instead of 0                 return super().__getitem__(index - 1)             else:                 raise IndexError(\"Index must be between 1 and 5 inclusive.\")      home_part = CustomIndexedList(map(lambda i: f'.smh__part.smh__home.smh__part--{i}', range(1, 6)))     away_part = CustomIndexedList(map(lambda i: f'.smh__part.smh__away.smh__part--{i}', range(1, 6)))      total_button = '[title=\"Over\/Under\"]'     handicap_button = '[title=\"Asian handicap\"]'     home_away = '[title=\"Home\/Away\"]'      coef_box = '.ui-table__body'      # This selectors often change by site owners     odds_on_bar = 'button._tab_33oei_5:has-text(\"Odds\")'     handicap_quarter1 = 'button._tab_33oei_5:has-text(\"1st Qrt\")'<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0438\u044f \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u0435\u0439 \u0432 \u0431\u0430\u0441\u043a\u0435\u0442\u0431\u043e\u043b\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u043f\u0435\u0440\u0432\u043e\u0439, \u0434\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u043b \u0441\u043f\u043e\u0441\u043e\u0431 \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u044f\u043c (\u0447\u0442\u043e \u0432 \u0438\u0442\u043e\u0433\u0435 \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435 \u043b\u0438\u0448\u0435\u043d\u043e \u0441\u043c\u044b\u0441\u043b\u0430).<\/p>\n<p>\u0421\u0435\u043b\u0435\u043a\u0442\u043e\u0440 odds_on_bar, \u043e\u043f\u044f\u0442\u044c-\u0442\u0430\u043a\u0438, \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u0441 \u0442\u0435\u0447\u0435\u043d\u0438\u0435\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0442\u0435\u0441\u0442\u043e\u043c:<\/p>\n<pre><code class=\"python\">#test_selector_validity.py  import pytest from playwright.sync_api import sync_playwright  odds_on_bar = 'button._tab_33oei_5:has-text(\"Odds\")' @pytest.mark.parametrize(\"link\", [     'https:\/\/www.basketball24.com\/match\/v5QYCKw8',     'https:\/\/www.basketball24.com\/match\/Aeu3mByg',     'https:\/\/www.basketball24.com\/match\/WWG7ksfA' ]) def test_selector_presence(link):     with sync_playwright() as p:         browser = p.chromium.launch()         context = browser.new_context()         page = context.new_page()         page.goto(link)          selector_exists = page.query_selector(odds_on_bar) is not None          assert selector_exists, f\"Selector {odd_on_bar} not found on the page {link}\"<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f link_collector \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0442 \u0432\u0441\u0435 \u043d\u0443\u0436\u043d\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438. \u0412 \u043a\u043e\u043d\u0446\u0435 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u044e\u0442 \u0432\u0441\u0435 \u0432\u043a\u043b\u0430\u0434\u043a\u0438 \u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440, \u0430 \u0437\u0430\u0442\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442 \u043f\u043e\u0441\u0442\u0440\u043e\u0447\u043d\u043e \u0441\u0441\u044b\u043b\u043a\u0438 \u0432 txt-\u0444\u0430\u0439\u043b\u0438\u043a. link_collector.py \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f, \u0441 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u0432 \u0432\u0438\u0434\u0435 URL.<\/p>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0432\u0441\u0435 \u043c\u0430\u0442\u0447\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u043f\u044f\u0442\u0438 \u0441\u0435\u0437\u043e\u043d\u043e\u0432 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\u043e\u0432, \u0438\u0434\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435. \u041a\u0430\u0436\u0434\u0430\u044f \u0438\u0437 \u044d\u0442\u0438\u0445 \u0441\u0441\u044b\u043b\u043e\u043a \u0438\u043c\u0435\u0435\u0442 \u0442\u0430\u043a\u043e\u0439 \u0432\u0438\u0434:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/923\/161\/858\/92316185883687c5e2d63b167728bd1d.png\" alt=\"\u0418\u043d\u043e\u0433\u0434\u0430 \u043d\u0430 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u043b\u0438\u0433\u0430 \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0431\u044b\u0442\u044c \u0432\u043a\u043b\u0430\u0434\u043e\u043a ODDS\" title=\"\u0418\u043d\u043e\u0433\u0434\u0430 \u043d\u0430 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u043b\u0438\u0433\u0430 \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0431\u044b\u0442\u044c \u0432\u043a\u043b\u0430\u0434\u043e\u043a ODDS\" width=\"685\" height=\"638\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/923\/161\/858\/92316185883687c5e2d63b167728bd1d.png\"\/><\/p>\n<div><figcaption>\u0418\u043d\u043e\u0433\u0434\u0430 \u043d\u0430 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u043b\u0438\u0433\u0430 \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0431\u044b\u0442\u044c \u0432\u043a\u043b\u0430\u0434\u043e\u043a ODDS<\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430\u0438 \u0441\u0441\u044b\u043b\u043e\u043a \u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0434\u0432\u0430 \u043c\u043e\u0434\u0443\u043b\u044f:<\/p>\n<pre><code class=\"python\">#main_handler.py  import psycopg2 from playwright.sync_api import sync_playwright from abc import ABC, abstractmethod from details.main_selectors import Selectors  class MatchHandler:     def __init__(self, links, url):         self.links = links         self.__url = url         self.match_title = None         self.scoreline = None         self.coefs = None         self.league_id = None         self.league_name = None         self.browser = None         self.context = None         self.page = None         if links != 1:             self.get_league_id()      def reset_data(self):         self.match_title = None         self.scoreline = None         self.coefs = None      def is_match_exists(self, match_data):         conn = psycopg2.connect(             host=\"127.0.0.1\",             user=\"postgres\",             password=\"123456er\",             port=\"5432\",             dbname= ]         )         cur = conn.cursor()          select_match_query = \"\"\"         SELECT match_id FROM matches         WHERE league_id = %s           AND match_date = %s           AND team_home = %s           AND team_away = %s         \"\"\"         cur.execute(select_match_query, match_data[:4])         match_id = cur.fetchone()          conn.close()          return match_id is not None      def open_browser_and_process_links(self):         with sync_playwright() as p:             self.browser = p.chromium.launch(headless=False)             self.context = self.browser.new_context()             self.page_empty = self.context.new_page()               self.create_match_tables()              for link in self.links:                 try:                     self.page = self.context.new_page()                      self.reset_data()                      self.page.goto(link)                     self.page.wait_for_selector(Selectors.scoreline)                     self.process_title()                     self.process_scoreline()                     self.process_coefs()                      match_data = (self.league_id, self.match_title[1],                                   self.match_title[3], self.match_title[4])                      if self.is_match_exists(match_data):                         print(f\"Match already exists: {self.match_title}\")                         continue  #\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c -> continue, \u043f\u0440\u0435\u043a\u0440\u0430\u0449\u0430\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0432\u0441\u0435\u0445 \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0445\u0441\u044f \u0441\u0441\u044b\u043b\u043e\u043a(\u043a\u043e\u0433\u0434\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e \u0443\u0436\u0435 \u043d\u0430\u043a\u0430\u0447\u0430\u043d\u043d\u0443\u044e \u0431\u0430\u0437\u0443) -> break                     else:                         print('-----')                         print(self.match_title)                         print(self.scoreline)                         print(self.coefs)                         print('-----')                         self.page.close()                         self.save_to_database(self.match_title,                                               self.scoreline,                                               self.coefs)                 except Exception as e:                     print(e)                     self.save_failed_link(link)                     print('ok8')                     self.page.close()                     continue        def save_failed_link(self, link):         file_name = '-'.join(self.__url.split('\/')[-2:])         with open(f\"details\\\\txt_links\\\\failed\\\\{file_name}.txt\", 'a') as file:             file.write(link + \"\\n\")             print('Failed link has been saved')      @abstractmethod     def create_match_tables(self):         pass      @abstractmethod     def process_scoreline(self):         pass      @abstractmethod     def process_coefs(self):         pass      @abstractmethod     def save_to_database(self, title, scores, coefs):         pass       def process_title(self):         team_home_element = self.page.query_selector(Selectors.team_home)         team_away_element = self.page.query_selector(Selectors.team_away)         tournament_header = self.page.query_selector(Selectors.tournament)         date_header = self.page.query_selector(Selectors.date_and_time)         final_score_header = self.page.query_selector(Selectors.final_score)         full_time_score = self.page.query_selector(Selectors.fulltime_score)          team_home = team_home_element.text_content().strip() if team_home_element else None         team_away = team_away_element.text_content().strip() if team_away_element else None         tournament = tournament_header.text_content() if tournament_header else None         date_and_time = date_header.text_content() if date_header else None         final_score = final_score_header.text_content() if final_score_header else None         score_ft = full_time_score.text_content() if full_time_score else None          stage = self.extract_stage(tournament)         date, start_time = self.extract_date_and_time(date_and_time)         home_score, away_score, home_score_ft, away_score_ft = self.extract_scores(final_score, score_ft)         total_result = home_score_ft + away_score_ft          match_data =  (self.league_id, date, start_time,                        team_home, team_away, self.league_name, stage,                        home_score, away_score, home_score_ft, away_score_ft, total_result)         self.match_title = match_data      def extract_stage(self, tournament):         if tournament:             print(tournament)             colon_index = tournament.find(\":\")             if colon_index != -1:                 stage_part = tournament[colon_index + 1:].strip()                 if '-' in stage_part:                     stage = stage_part.split('-', 1)[1].strip().upper()                     if 'ALL' in stage:                         stage = 'ALL STARS'                     if \"SEMI-FINALS\" in stage or \"QUARTER-FINALS\" in stage or \"1\/8-FINALS\" in stage or \"PROMOTION\" in stage:                         stage = \"PLAY OFFS\"                     elif \"FINAL\" in stage:                         stage = \"FINAL\"                     elif \"ROUND\" in stage or \"NBA\" in stage:                         stage = \"MAIN\"                     return stage          return \"MAIN\"      def extract_date_and_time(self, date_and_time):         if date_and_time:             date = date_and_time.split()[0]             start_time = date_and_time.split()[1]             return date, start_time         return None, None      def extract_scores(self, final_score, score_ft):         if final_score:             home_score = int(final_score.split('-')[0])             away_score = int(final_score.split('-')[1])         else:             home_score, away_score = None, None          if score_ft is None:             home_score_ft, away_score_ft = home_score, away_score         else:             home_score_ft = int(score_ft.split('-')[0].replace('(',''))             away_score_ft = int(score_ft.split('-')[1].replace(')',''))          return home_score, away_score, home_score_ft, away_score_ft       def get_league_id(self):         conn = psycopg2.connect(             host=\"127.0.0.1\",             user=\"postgres\",             password=\"123456er\",             port=\"5432\"         )         cur = conn.cursor()         cur.execute(f\"SELECT id, league FROM championships WHERE link = '{self.__url}'\")         data = cur.fetchall()         conn.close()         print(data)         self.league_id = data[0][0]         self.league_name = data[0][1]<\/code><\/pre>\n<p>\u0418<\/p>\n<pre><code class=\"python\">#basketball_handler.py  import psycopg2 from sport_handlers.main_handler import MatchHandler from details.main_selectors import Selectors import time   class Basketball(MatchHandler):     def __init__(self, links, url):         super().__init__(links, url)       def create_match_tables(self):         conn = psycopg2.connect(             host=\"127.0.0.1\",             user=\"postgres\",             password=\"123456er\",             port=\"5432\"         )         cur = conn.cursor()          # SQL-\u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b matches         create_matches_table_query = \"\"\"         CREATE TABLE IF NOT EXISTS matches (             match_id SERIAL PRIMARY KEY,             league_id INTEGER,             match_date DATE,             start_time TIME,             team_home VARCHAR(255),             team_away VARCHAR(255),             league_name VARCHAR(255),             stage VARCHAR(255),             home_score INTEGER,             away_score INTEGER,             home_score_ft INTEGER,             away_score_ft INTEGER,             total_ft INTEGER         );         \"\"\"          cur.execute(create_matches_table_query)          # SQL-\u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b match_details         create_match_details_table_query = \"\"\"         CREATE TABLE IF NOT EXISTS details (             match_id INTEGER PRIMARY KEY REFERENCES matches(match_id),             home_q1 INTEGER,             away_q1 INTEGER,             home_q2 INTEGER,             away_q2 INTEGER,             home_q3 INTEGER,             away_q3 INTEGER,             home_q4 INTEGER,             away_q4 INTEGER,             home_ot INTEGER,             away_ot INTEGER,             home_win REAL,             away_win REAL,             total REAL,             handicap REAL,             hc_q1 REAL         );         \"\"\"          cur.execute(create_match_details_table_query)          try:             add_constraint_query = \"\"\"                    ALTER TABLE matches                    ADD CONSTRAINT unique_match_constraint UNIQUE (league_id, match_date, start_time, team_home, team_away);                    \"\"\"              cur.execute(add_constraint_query)         except psycopg2.errors.DuplicateTable:             pass          conn.commit()         conn.close()       def save_to_database(self, title, scores, coefs):         if not title or not scores or not coefs:             return          conn = psycopg2.connect(             host=\"127.0.0.1\",             user=\"postgres\",             password=\"123456er\",             port=\"5432\",         )         cur = conn.cursor()          try:             # SQL \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 matches             insert_match_query = \"\"\"             INSERT INTO matches (league_id, match_date, start_time, team_home, team_away, league_name, stage,                                 home_score, away_score, home_score_ft, away_score_ft, total_ft)             VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)             RETURNING match_id             \"\"\"             cur.execute(insert_match_query, title)             match_id = cur.fetchone()[0]              # SQL-\u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 match_details             insert_details_query = \"\"\"             INSERT INTO details (match_id, home_q1, away_q1, home_q2, away_q2, home_q3, away_q3,                                   home_q4, away_q4, home_ot, away_ot, home_win, away_win, total, handicap, hc_q1)             VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)             \"\"\"             cur.execute(insert_details_query, (match_id,) + scores + coefs)              conn.commit()          except Exception as e:             print('Error with saving')             print(e)          conn.close()       def process_scoreline(self):         home_parts = Selectors.home_part         away_parts = Selectors.away_part         try:             home_scores = [self.get_int_score(self.page.query_selector(part)) for part in home_parts]             away_scores = [self.get_int_score(self.page.query_selector(part)) for part in away_parts]             scores_data = [item for pair in zip(home_scores, away_scores) for item in pair]         except Exception as e:             scores_data = [None]*10             print('Erorr with scoreline handling', e.with_traceback())          self.scoreline = tuple(scores_data)         print(scores_data)      def process_coefs(self):         home_win = None         away_win = None         average_total = None         average_handicap = None         average_handicap_q1 = None          def process_coef_button(selector):             self.page.wait_for_selector(selector, timeout=3000)             element = self.page.query_selector(selector)              if element:                 element.click()                 self.page.wait_for_selector(Selectors.coef_box)                 all_coefs = [i.inner_text() for i in self.page.query_selector_all(Selectors.coef_box)]                 return self.find_average_value(all_coefs)             return None          try:             self.page.query_selector(Selectors.odds_on_bar).click()             self.page.wait_for_selector(Selectors.coef_box)         except:             print('No odds section')             pass          try:             if self.page.query_selector(Selectors.home_away):                 coefs_text = self.page.query_selector(Selectors.coef_box).inner_text().split()[:2]                 home_win = float(coefs_text[0])         except:             home_win = 1.0          try:             if self.page.query_selector(Selectors.home_away):                 coefs_text = self.page.query_selector(Selectors.coef_box).inner_text().split()[:2]                 away_win = float(coefs_text[1])         except:             away_win = 1.0          try:             average_total = process_coef_button(Selectors.total_button)         except Exception as e:             print(f\"Error processing total button: {e}\")             average_total = None          try:             average_handicap = process_coef_button(Selectors.handicap_button)         except Exception as e:             print(f\"Error processing handicap button: {e}\")             average_handicap = None          try:             average_handicap_q1 = process_coef_button(Selectors.handicap_quarter1)         except Exception as e:             print(f\"Error processing handicap quarter 1 button: {e}\")             average_handicap_q1 = None          coefs = (home_win, away_win, average_total, average_handicap, average_handicap_q1)         self.coefs = coefs         print(self.coefs, '&lt;-')       @staticmethod     def find_average_value(coefline):         k = None         value = None         min_diff = 100         for case in coefline:             current_total = case.split()[0]             k1, k2 = list(map(float, case.split()[1:3]))             diff = abs(k1 - k2)             if diff &lt; min_diff:                 min_diff = diff                 value = current_total         print(f\"The total\/handicap with the smallest diff is: {value}\")         return float(value)       @staticmethod     def get_int_score(element):         if element:             content = element.text_content()             try:                 return int(content) if content else None             except ValueError:                 return None         else:             return None<\/code><\/pre>\n<p>\u0412 \u043f\u0435\u0440\u0432\u043e\u043c \u043c\u043e\u0434\u0443\u043b\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043b\u0430\u0441\u0441 MatchHandler \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043b\u043e\u0433\u0438\u043a\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043c\u0430\u0442\u0447\u0435\u0439 \u0438 \u0432 \u0441\u0435\u0431\u0435 \u0438\u043c\u0435\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 process_title. \u0422\u0430\u043a \u043a\u0430\u043a \u0432 \u0446\u0435\u043b\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u0430\u0440\u0441\u0438\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0430\u0441\u043a\u0435\u0442\u0431\u043e\u043b, \u043d\u043e \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0432\u0438\u0434\u044b \u0441\u043f\u043e\u0440\u0442\u0430, \u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u043c\u0430\u0442\u0447\u0430 \u0432\u0435\u0437\u0434\u0435 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u0430\u044f. \u0410\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0435 \u0436\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0441\u0447\u0435\u0442\u0435 \u0438 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u0430\u0445 \u0434\u043b\u044f \u0431\u0430\u0441\u043a\u0435\u0442\u0431\u043e\u043b\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 Basketball. \u0422\u0430\u043a\u0436\u0435 \u0432 MatchHandler \u0435\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f save_failed_link, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0432 \u043f\u0430\u043f\u043a\u0443 failed \u0441\u0441\u044b\u043b\u043a\u0438, \u043f\u043e \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c. \u0418\u0445 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e. \u0412 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0430\u0440\u0443\u0448\u0438\u0442\u0441\u044f \u0445\u0440\u043e\u043d\u043e\u043b\u043e\u0433\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439(\u043c\u0430\u0442\u0447\u0435\u0439). \u041f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0439 \u043d\u0435\u0443\u0434\u0430\u0447\u0435, \u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u043d\u0435\u0441\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0432 \u0431\u0434.  <\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432\u0441\u0435 \u044d\u0442\u043e \u0434\u0435\u043b\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"python\">#main_run.py  import subprocess from sport_handlers.basketball_handler import Basketball from sport_handlers.main_handler import MatchHandler  #\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u044e\u0434\u0430 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\u044b ,\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0445\u043e\u0442\u0438\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c, \u0436\u0430\u0434\u043d\u0438\u0447\u0430\u0442\u044c \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 - #\u043e\u0434\u0438\u043d \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 2-3 \u0447\u0430\u0441\u0430 urls = [  \"https:\/\/www.basketball24.com\/iceland\/premier-league\",  ]   for url in urls:     subprocess.run(['python', 'link_collector.py', url], check=True)     file_name = '-'.join(url.split('\/')[-2:])     print(file_name)     with open(f\"details\\\\txt_links\\\\{file_name}.txt\", 'r') as file:         links = [line.strip() for line in file.readlines()]     basketball_handler = Basketball(links, url)     basketball_handler.open_browser_and_process_links()<\/code><\/pre>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u043d\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"python\">#failed_run.py  import subprocess from sport_handlers.basketball_handler import Basketball from sport_handlers.main_handler import MatchHandler   urls = [  \"https:\/\/www.basketball24.com\/south-korea\/kbl\", \"https:\/\/www.basketball24.com\/switzerland\/sb-league\"   ]   for url in urls:     file_name = '-'.join(url.split('\/')[-2:])     print(file_name)     with open(f\"details\\\\txt_links\\\\failed\\\\{file_name}.txt\", 'r') as file:         links = [line.strip() for line in file.readlines()]     basketball_handler = Basketball(links, url)     basketball_handler.open_browser_and_process_links()<\/code><\/pre>\n<p>\u0421\u043b\u0435\u0434\u0443\u0435\u0442 \u0443\u0447\u0435\u0441\u0442\u044c \u0447\u0442\u043e \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0448\u0438\u0431\u043e\u043a, \u0432 urls \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u043d \u0442\u043e\u0442 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442 , \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0438 \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043c\u0430\u0442\u0447\u0435\u0439.<\/p>\n<h2>\u0418\u0442\u043e\u0433\u043e \u0438\u043c\u0435\u0435\u043c<\/h2>\n<p>\u042f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043b \u0448\u0430\u0440\u043c\u0430\u043d\u043a\u0443 \u0441 \u0440\u0430\u043d\u0434\u043e\u043c\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c\u0438 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\u0430\u043c\u0438, \u043a\u043e\u0438\u0445 \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c 47, \u0438 \u043e\u0442\u043e\u0448\u0451\u043b \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u043d\u0435\u0439 \u043e\u0442 \u043d\u043e\u0443\u0442\u0430 \u043f\u043e\u0434\u0430\u043b\u044c\u0448\u0435))  <\/p>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432\u044b\u0448\u0435\u043b \u0442\u0430\u043a\u0438\u043c:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/1e9\/cdc\/111\/1e9cdc1116a0933c505f26a00e4b5bc4.png\" alt=\"\u0442\u0430\u0431\u043b\u0438\u0446\u0430 matches\" title=\"\u0442\u0430\u0431\u043b\u0438\u0446\u0430 matches\" width=\"1872\" height=\"677\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1e9\/cdc\/111\/1e9cdc1116a0933c505f26a00e4b5bc4.png\"\/><\/p>\n<div><figcaption>\u0442\u0430\u0431\u043b\u0438\u0446\u0430 matches<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c89\/86d\/085\/c8986d0859abd6e5fcba87b93c6739bb.png\" alt=\"\u0442\u0430\u0431\u043b\u0438\u0446\u0430 details\" title=\"\u0442\u0430\u0431\u043b\u0438\u0446\u0430 details\" width=\"1351\" height=\"690\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c89\/86d\/085\/c8986d0859abd6e5fcba87b93c6739bb.png\"\/><\/p>\n<div><figcaption>\u0442\u0430\u0431\u043b\u0438\u0446\u0430 details<\/figcaption><\/div>\n<\/figure>\n<p>\u0413\u043b\u044f\u043d\u0443\u043b &#8212; \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0441\u0435\u0433\u043e \u043c\u0430\u0442\u0447\u0435\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e\u0441\u044c:<\/p>\n<pre><code class=\"pgsql\">select count(*) from matches;<\/code><\/pre>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b3f\/ec0\/fdc\/b3fec0fdc598002376674588d614a9bc.png\" alt=\"\u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043f\u043e 1000 \u043c\u0430\u0442\u0447\u0435\u0439 \u043d\u0430 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\" title=\"\u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043f\u043e 1000 \u043c\u0430\u0442\u0447\u0435\u0439 \u043d\u0430 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\" width=\"83\" height=\"74\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b3f\/ec0\/fdc\/b3fec0fdc598002376674588d614a9bc.png\"\/><\/p>\n<div><figcaption>\u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043f\u043e 1000 \u043c\u0430\u0442\u0447\u0435\u0439 \u043d\u0430 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442<\/figcaption><\/div>\n<\/figure>\n<p>\u0412\u043e\u043e\u0431\u0449\u0435\u043c-\u0442\u043e \u0432\u0441\u0435, \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0433\u0438\u0431\u043a\u0438\u0439 \u043f\u0430\u0440\u0441\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u043e\u0434 \u043b\u044e\u0431\u043e\u0439 \u0432\u0438\u0434 \u0441\u043f\u043e\u0440\u0442\u0430 \u0438 \u0440\u0435\u0433\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0435\u0437\u043e\u043d\u043e\u0432 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/p>\n<h2>PS<\/h2>\n<p>\u0414\u043b\u044f \u0437\u0430\u0442\u0440\u0430\u0432\u043a\u0438, \u0442\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0447\u0430\u0441\u0442\u044c, \u0435\u0441\u043b\u0438 \u043a\u043e\u043c\u0443-\u0442\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u0432\u043e\u0442, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u0431\u0430\u043d\u0430\u043b\u044c\u043d\u044b\u0439 SQL-\u0437\u0430\u043f\u0440\u043e\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u043c \u0438 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u044b\u043c:  <\/p>\n<pre><code class=\"pgsql\">SELECT     COUNT(CASE WHEN m.total_ft > d.total THEN 1 END) AS total_ft_greater,     COUNT(CASE WHEN m.total_ft &lt; d.total THEN 1 END) AS total_ft_less FROM     matches m JOIN     details d ON m.match_id = d.match_id; <\/code><\/pre>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/aa9\/452\/5fc\/aa94525fc5de7b42972826b02e99330e.png\" alt=\"\u0435\u0449\u0435 1114 \u043c\u0430\u0442\u0447\u0435\u0439 \u0440\u043e\u0432\u043d\u043e \u043f\u043e\u043f\u0430\u043b\u043e \u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0442\u043e\u0442\u0430\u043b\u0430 \" title=\"\u0435\u0449\u0435 1114 \u043c\u0430\u0442\u0447\u0435\u0439 \u0440\u043e\u0432\u043d\u043e \u043f\u043e\u043f\u0430\u043b\u043e \u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0442\u043e\u0442\u0430\u043b\u0430 \" width=\"306\" height=\"62\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/aa9\/452\/5fc\/aa94525fc5de7b42972826b02e99330e.png\"\/><\/p>\n<div><figcaption>\u0435\u0449\u0435 1114 \u043c\u0430\u0442\u0447\u0435\u0439 \u0440\u043e\u0432\u043d\u043e \u043f\u043e\u043f\u0430\u043b\u043e \u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0442\u043e\u0442\u0430\u043b\u0430 <\/figcaption><\/div>\n<\/figure>\n<p>\u041e\u043d \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0430\u0442\u0447\u0435\u0439 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u043e\u0441\u044c \u0441 \u0442\u043e\u0442\u0430\u043b\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u0435, \u0447\u0435\u043c \u0431\u044b\u043b \u0434\u0430\u043d \u0431\u0443\u043a\u043c\u0435\u043a\u0435\u0440\u043e\u043c, \u0438 \u0441 \u0442\u043e\u0442\u0430\u043b\u043e\u043c \u043c\u0435\u043d\u044c\u0448\u0435. \u0418 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u043d\u0430 \u0434\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u0438 47386 \u043c\u0430\u0442\u0447\u0435\u0439, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0444\u0438\u043b\u0438\u0433\u0440\u0430\u043d\u043d\u043e \u0442\u043e\u0447\u043d\u043e \u0431\u0443\u043a\u043c\u0435\u043a\u0435\u0440 \u0432 \u0441\u0440\u0435\u0434\u043d\u0435\u043c \u0434\u0430\u0435\u0442 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u0422\u043e \u0435\u0441\u0442\u044c \u043f\u043e\u0447\u0442\u0438 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u043c\u0430\u0442\u0447\u0435\u0439 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u043e\u0441\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0438 \u043c\u0435\u043d\u044c\u0448\u0435 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041f\u043e \u043f\u0440\u0438\u043a\u043e\u043b\u0443 \u0440\u0430\u0441\u0447\u0435\u0442: \u0435\u0441\u043b\u0438 \u0432\u0437\u044f\u0442\u044c \u0431\u0443\u043a\u043c\u0435\u043a\u0435\u0440\u0441\u043a\u0443\u044e \u043c\u0430\u0440\u0436\u0443 5%, \u0430 \u044d\u0442\u043e \u0431\u0443\u0434\u0443\u0442 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u044b 1.90 \/ 1.90 \u043d\u0430 \u0442\u043e\u0442\u0430\u043b \u0431\u043e\u043b\u044c\u0448\u0435 \u0438 \u0442\u043e\u0442\u0430\u043b \u043c\u0435\u043d\u044c\u0448\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u043e 100 \u0440\u0443\u0431\u043b\u0435\u0439 \u043d\u0430 \u0442\u043e\u0442\u0430\u043b \u0431\u043e\u043b\u044c\u0448\u0435 \u0438\u043b\u0438 \u0442\u043e\u0442\u0430\u043b \u043c\u0435\u043d\u044c\u0448\u0435:<\/p>\n<p><em>47\u00a0386\u00a0* 100\u00a0= 4\u00a0738\u00a0600\u00a0\u2014 \u0443\u0448\u043b\u043e \u043d\u0430\u00a0\u0432\u0441\u0435 \u0441\u0442\u0430\u0432\u043a\u0438<\/em><\/p>\n<p><em>1114\u00a0* 100\u00a0= 111\u00a0400\u00a0\u2014 \u0432\u0435\u0440\u043d\u0443\u043b\u043e\u0441\u044c \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043e\u043c, \u043a\u043e\u0433\u0434\u0430 \u0442\u043e\u0442\u0430\u043b \u0440\u043e\u0432\u043d\u043e \u0441\u043e\u0432\u043f\u0430\u043b<\/em><\/p>\n<p><em>23\u00a0084*100*1.9\u00a0= 4\u00a0385\u00a0960\u00a0\u2014 \u0432\u0430\u0448 \u0432\u044b\u0438\u0433\u0440\u044b\u0448, \u043f\u0440\u0438\u00a0\u0441\u0442\u0430\u0432\u043a\u0435 \u043d\u0430\u00a0\u0442\u043e\u0442\u0430\u043b \u0431\u043e\u043b\u044c\u0448\u0435<\/p>\n<p>23\u00a0188\u00a0* 100\u00a0* 1.9\u00a0= 4\u00a0405\u00a0720\u00a0\u2014 \u0432\u0430\u0448 \u0432\u044b\u0438\u0433\u0440\u044b\u0448, \u043f\u0440\u0438\u00a0\u0441\u0442\u0430\u0432\u043a\u0435 \u043d\u0430\u00a0\u0442\u043e\u0442\u0430\u043b \u043c\u0435\u043d\u044c\u0448\u0435<\/p>\n<p>\u0412\u0430\u0448 \u0434\u043e\u0445\u043e\u0434:<br \/>4\u00a0385\u00a0960\u00a0+ 111\u00a0400\u00a0\u2014 4\u00a0738\u00a0600\u00a0= <\/em><strong><em>-241 240<\/em><\/strong><em>\u00a0\u0440\u0443\u0431 (\u043f\u0440\u0438 \u0441\u0442\u0430\u0432\u043a\u0430\u0445 \u043d\u0430\u00a0\u0442\u043e\u0442\u0430\u043b \u0431\u043e\u043b\u044c\u0448\u0435)<br \/>4\u00a0405\u00a0720\u00a0+ 111\u00a0400\u00a0\u2014 4\u00a0738\u00a0600\u00a0= <\/em><strong><em>-221 480<\/em><\/strong><em>\u00a0\u0440\u0443\u0431 (\u043f\u0440\u0438 \u0441\u0442\u0430\u0432\u043a\u0430\u0445 \u043d\u0430\u00a0\u0442\u043e\u0442\u0430\u043b \u043c\u0435\u043d\u044c\u0448\u0435)<\/em><\/p>\n<p>&#171;\u0414\u043e\u0445\u043e\u0434\u044b&#187;, \u043d\u0430\u0434\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c ,\u0441\u043a\u0440\u043e\u043c\u043d\u044b\u0435).\u0422\u0430\u043a \u0447\u0442\u043e \u0431\u0443\u0434\u044c\u0442\u0435  \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u044b \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441\u043e \u0441\u0442\u0430\u0432\u043a\u0430\u043c\u0438 \u0438 \u043b\u0443\u0447\u0448\u0435 \u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u0445 \u0441\u0442\u0430\u0432\u043e\u043a, \u0434\u043b\u044f \u043b\u0430\u0439\u0432\u0430 \u044f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f <a href=\"https:\/\/bet-hub.com\/\" rel=\"noopener noreferrer nofollow\">bet-hub.com<\/a>, \u0430 \u0434\u043b\u044f \u043f\u0440\u0435\u043c\u0430\u0442\u0447 <a href=\"https:\/\/expari.com\/\" rel=\"noopener noreferrer nofollow\">expari.com<\/a>. \u0422\u0430\u043a \u0432\u0430\u0448\u0438 \u0434\u043e\u0445\u043e\u0434\u044b \u043e\u0441\u0442\u0430\u043d\u0443\u0442\u0441\u044f \u043d\u0430 \u0434\u043e\u0441\u0442\u043e\u0439\u043d\u043e\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0438 == 0.<\/p>\n<p>\u041d\u0443 \u0438 \u043d\u0435 \u0432\u0441\u0435 \u0442\u0430\u043a \u043f\u043b\u043e\u0445\u043e, \u043a\u0430\u043a \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434. SQL \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043c \u043f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u044b \u043d\u0430 \u0438\u0441\u0442\u043e\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u0447\u0442\u043e\u0431\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0432 \u0433\u0440\u0430\u0444\u0435 \u0434\u043e\u0445\u043e\u0434 \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043d\u0430\u0442\u0443\u0440\u0430\u043b\u044c\u043d\u044b\u0435 \u0447\u0438\u0441\u043b\u0430.  <\/p>\n<p>\u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0431\u0435\u0440\u0435\u0433\u0438\u0442\u0435 \u0441\u0435\u0431\u044f, \u0441\u0432\u043e\u0438 \u043d\u0435\u0440\u0432\u044b \u0438 \u0441\u0432\u043e\u0439 \u043a\u044d\u0448! Ciao!  <\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/791810\/\"> https:\/\/habr.com\/ru\/articles\/791810\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h3>\u041f\u0440\u043e\u043b\u043e\u0433<\/h3>\n<p>Hello, ladies and gentlemen!  <\/p>\n<p>\u0420\u0435\u0448\u0438\u043b \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0443\u043f\u0440\u0430\u0436\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u043f\u0443\u0431\u043b\u0438\u0446\u0438\u0441\u0442\u0438\u043a\u0435, \u0442\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u043f\u0435\u0440\u0432\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e. \u0422\u0430\u043a \u0447\u0442\u043e \u043d\u0435 \u0441\u0443\u0434\u0438\u0442\u0435 \u0441\u0442\u0440\u043e\u0433\u043e.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u043b\u044c\u0432\u0438\u043d\u0443\u044e \u0434\u043e\u043b\u044e \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u044f \u0442\u0440\u0430\u0442\u0438\u043b \u043d\u0430 \u043f\u043e\u0438\u0441\u043a\u0438 \u0440\u0430\u0431\u043e\u0442\u044b\/\u0441\u0442\u0430\u0436\u0438\u0440\u043e\u0432\u043a\u0438 \u0442\u0435\u0441\u0442\u0435\u0440\u043e\u0432\u0449\u0438\u043a\u043e\u043c.  \u0414\u0435\u043b\u043e \u044d\u0442\u043e \u043a\u0430\u043a \u0432\u044b\u044f\u0441\u043d\u0438\u043b\u043e\u0441\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0443\u0442\u043e\u043c\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0438 \u043d\u0435\u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u043d\u043e\u0435, \u043a \u0442\u043e\u043c\u0443 \u0436\u0435 \u0437\u0430 \u043f\u0440\u0430\u0437\u0434\u043d\u044b\u043c \u0432\u0440\u0435\u043c\u044f\u043f\u0440\u0435\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0448\u044c \u043f\u043e\u0442\u0438\u0445\u043e\u043d\u044c\u043a\u0443 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c \u0431\u0430\u0437\u0443, \u0442\u0430\u043a \u0447\u0442\u043e \u0440\u0435\u0448\u0438\u043b \u0441 \u044d\u0442\u0438\u043c \u0434\u0435\u043b\u043e\u043c \u043f\u0440\u0438\u0442\u043e\u0440\u043c\u043e\u0437\u0438\u0442\u044c, \u0441\u043b\u0435\u0433\u043a\u0430 \u0440\u0430\u0437\u0432\u0435\u044f\u0442\u044c\u0441\u044f \u0438 \u043a\u043e\u0435-\u0447\u0442\u043e \u043f\u043e\u0432\u0441\u043f\u043e\u043c\u0438\u043d\u0430\u0442\u044c. <\/p>\n<p>\u041f\u043e\u043d\u044f\u0442\u0438\u0435 &#171;\u0431\u0430\u0437\u0430&#187;, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0440\u0430\u0441\u0442\u044f\u0436\u0438\u043c\u043e\u0435. \u0414\u043b\u044f \u0441\u0435\u0431\u044f \u044f \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u0437\u044f\u043b Python \u0438 SQL.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0440\u0435\u0447\u044c \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u0439\u0434\u0435\u0442 \u043e \u0441\u0431\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u043e \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0435\/\u0441\u043a\u0440\u0430\u043f\u043f\u0438\u043d\u0433\u0435 (\u043a\u0442\u043e \u043a\u0430\u043a \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u0435\u0442), \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u043c \u0430\u043d\u0430\u043b\u0438\u0437\u0435 \u044d\u0442\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 Python \u0431\u0443\u0434\u0443\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044b \u0442\u0430\u043a\u0438\u0435 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043a\u0430\u043a Playwright, Requests, bs4, \u0438 psycopg2(\u043d\u0430\u0434\u043e \u0436\u0435 \u043a\u0443\u0434\u0430-\u0442\u043e \u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c).<\/p>\n<p>\u042d\u0442\u043e\u0442 \u043d\u0435\u0437\u0430\u043c\u044b\u0441\u043b\u043e\u0432\u0430\u0442\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u043d\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043f\u043e\u0440\u0442\u0438\u0432\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 \u043f\u043e \u0431\u0430\u0441\u043a\u0435\u0442\u0431\u043e\u043b\u0443, \u0430 \u0442\u043e\u0447\u043d\u0435\u0435 \u0442\u0440\u0435\u0445 \u0442\u0430\u0431\u043b\u0438\u0446 \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u043e \u0432\u0441\u044f\u043a\u043e\u043c\u0443 \u043f\u043e\u0438\u0433\u0440\u0430\u0442\u044c\u0441\u044f.<\/p>\n<h3>\u041d\u0430\u0447\u0430\u043b\u043e<\/h3>\n<p>\u041c\u043d\u0435 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f UI \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u0441\u044f \u0441\u0435\u0440\u0432\u0438\u0441 flashscore.com. \u041e\u043d\u0438 \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u043f\u0430\u0440\u044f\u0442\u0441\u044f \u043f\u043e \u043f\u043e\u0432\u043e\u0434\u0443 \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043a\u043e\u0440\u044f\u0447\u0438\u0442\u044c\u0441\u044f \u0441\u043e \u0432\u0441\u044f\u043a\u0438\u043c\u0438 selenium-stealth \u0438 fakeuseragent-\u0430\u043c\u0438. \u0423 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u043e\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0431\u0430\u0441\u043a\u0435\u0442\u0431\u043e\u043b\u0430 &#8212; basketball24.com.<\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u044b \u0434\u0435\u043b\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f:<\/p>\n<ul>\n<li>\n<p>Python<\/p>\n<\/li>\n<li>\n<p>Playwright<\/p>\n<\/li>\n<li>\n<p>requests + bs4 (\u0434\u043b\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043c\u043e\u0436\u043d\u043e \u0432 \u043e\u0431\u0449\u0435\u043c-\u0442\u043e \u0431\u0435\u0437 \u043d\u0438\u0445)<\/p>\n<\/li>\n<li>\n<p>psycopg2 (\u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e postgresql)<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u043e\u0434\u043d\u044b\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0438\u0437 \u0441\u0435\u0440\u0438\u0438 json\/os\/sys \u0438 \u0442.\u0434.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0431\u0443\u0434\u0443 \u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0440\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0442\u0430\u043a\u043e\u0433\u043e \u0440\u043e\u0434\u0430:<\/p>\n<p>1.championships<strong>:<\/strong><\/p>\n<ul>\n<li>\n<p>id (\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043b\u0438\u0433\u0438)<\/p>\n<\/li>\n<li>\n<p>country (\u0441\u0442\u0440\u0430\u043d\u0430 \u043b\u0438\u0433\u0438)<\/p>\n<\/li>\n<li>\n<p>gender (\u043c\u0443\u0436\u0441\u043a\u043e\u0439 \u0438 \u0436\u0435\u043d\u0441\u043a\u0438\u0439)<\/p>\n<\/li>\n<li>\n<p>league (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043b\u0438\u0433\u0438)<\/p>\n<\/li>\n<li>\n<p>link (\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0430\u0440\u0445\u0438\u0432 \u0441\u043e \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u043e\u0439)<\/p>\n<\/li>\n<\/ul>\n<p>2.matches<strong>:<\/strong><\/p>\n<ul>\n<li>\n<p>match_id (\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043c\u0430\u0442\u0447\u0430)<\/p>\n<\/li>\n<li>\n<p>league_id (id \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b championships)<\/p>\n<\/li>\n<li>\n<p>match_date (\u0434\u0430\u0442\u0430 \u0432\u0441\u0442\u0440\u0435\u0447\u0438)<\/p>\n<\/li>\n<li>\n<p>start_time (\u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u0441\u0442\u0440\u0435\u0447\u0438, \u0443 \u043c\u0435\u043d\u044f UTC +01:00)<\/p>\n<\/li>\n<li>\n<p>team_home (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b)<\/p>\n<\/li>\n<li>\n<p>team_away (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043d\u0430 \u0432\u044b\u0435\u0437\u0434\u0435)<\/p>\n<\/li>\n<li>\n<p>league_name (\u0442\u043e \u0436\u0435 \u0447\u0442\u043e \u0438 league \u0438\u0437 championships)<\/p>\n<\/li>\n<li>\n<p>stage (\u044d\u0442\u0430\u043f \u0442\u0443\u0440\u043d\u0438\u0440\u0430)<\/p>\n<\/li>\n<li>\n<p>home_score (\u043e\u0447\u043a\u0438 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043e\u0432\u0435\u0440\u0442\u0430\u0439\u043c)<\/p>\n<\/li>\n<li>\n<p>away_score (\u043e\u0447\u043a\u0438 \u0433\u043e\u0441\u0442\u0435\u0432\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043e\u0432\u0435\u0440\u0442\u0430\u0439\u043c)<\/p>\n<\/li>\n<li>\n<p>home_score_ft (\u043e\u0447\u043a\u0438 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f)<\/p>\n<\/li>\n<li>\n<p>away_score_ft (\u043e\u0447\u043a\u0438 \u0433\u043e\u0441\u0442\u0435\u0432\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f)<\/p>\n<\/li>\n<li>\n<p>total_ft (\u043e\u0447\u043a\u0438 \u043e\u0431\u0435\u0438\u0445 \u043a\u043e\u043c\u0430\u043d\u0434 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f)<\/p>\n<\/li>\n<\/ul>\n<p>3.details<strong>:<\/strong><\/p>\n<ul>\n<li>\n<p>match_id (\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043c\u0430\u0442\u0447\u0430, \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b matches)<\/p>\n<\/li>\n<li>\n<p>home_q1 &#8230; away_ot (10 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432 \u0441 \u043d\u0430\u0431\u0440\u0430\u043d\u043d\u044b\u043c\u0438 \u043e\u0447\u043a\u0430\u043c\u0438 \u043a\u0430\u0436\u0434\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432 \u043e\u0432\u0435\u0440\u0442\u0430\u0439\u043c\u0435, \u0435\u0441\u043b\u0438 \u043e\u043d \u0431\u044b\u043b)<\/p>\n<\/li>\n<li>\n<p>home_win (\u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043d\u0430 \u043f\u043e\u0431\u0435\u0434\u0443 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b)<\/p>\n<\/li>\n<li>\n<p>away_win (\u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043d\u0430 \u043f\u043e\u0431\u0435\u0434\u0443 \u0433\u043e\u0441\u0442\u0435\u0432\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b)<\/p>\n<\/li>\n<li>\n<p>total (\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u0442\u043e\u0442\u0430\u043b\u0430 \u043d\u0430 \u0440\u0430\u0432\u043d\u044b\u0435 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u044b*)<\/p>\n<\/li>\n<li>\n<p>handicap (\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u0440\u0435\u0434\u043d\u0435\u0439 \u0444\u043e\u0440\u044b\/\u0433\u0430\u043d\u0434\u0438\u043a\u0430\u043f\u0430 \u043d\u0430 \u0440\u0430\u0432\u043d\u044b\u0435 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u044b* \u043f\u043e \u0438\u0442\u043e\u0433\u0443 \u043c\u0430\u0442\u0447\u0430)<\/p>\n<\/li>\n<li>\n<p>hc_q1 (\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u0440\u0435\u0434\u043d\u0435\u0439 \u0444\u043e\u0440\u044b\/\u0433\u0430\u043d\u0434\u0438\u043a\u0430\u043f\u0430 \u043d\u0430 \u0440\u0430\u0432\u043d\u044b\u0435 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u044b* \u043f\u043e \u0438\u0442\u043e\u0433\u0443 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u0438)<\/p>\n<p><em>*\u0440\u0430\u0432\u043d\u044b\u0435 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u044e \u0447\u0442\u043e \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0432\u0432\u0438\u0434\u0443 &#8212; \u043d\u0430 \u043c\u0430\u0442\u0447 \u0434\u0430\u044e\u0442 \u0441\u0440\u0435\u0434\u043d\u0438\u0439 \u0442\u043e\u0442\u0430\u043b 165.5 , \u0442\u043e \u0435\u0441\u0442\u044c \u043d\u0430 \u0422\u043e\u0442\u0430\u043b \u041c\u0435\u043d\u044c\u0448\u0435 165.5(\u0422\u041c) \u0434\u0430\u044e\u0442 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 1.87 \u0438 \u043d\u0430 \u0422\u043e\u0442\u0430\u043b \u0411\u043e\u043b\u044c\u0448\u0435 165.5(\u0422\u0411) &#8212; \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 1.87, \u0442\u043e \u0436\u0435 \u0438 \u0441 \u0444\u043e\u0440\u0430\u043c\u0438, \u0438\u043d\u043e\u0433\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b &#8212; 1.86 \u0438 1.88, 1.89 \u0438 1.85 , 1.9 \u0438 1.87 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e(\u0437\u0432\u0438\u0441\u044f\u0442 \u043e\u0442 \u043c\u0430\u0440\u0436\u0438 \u0431\u0443\u043a\u043c\u0435\u043a\u0435\u0440\u0430 \u0438 \u0432\u0435\u043b\u0438\u0447\u0438\u043d\u044b \u0440\u044b\u043d\u043a\u0430, \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u0438 \u0431\u043b\u0438\u0437\u043a\u0438 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u043d\u0430 \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u043b\u043e\u0436\u043d\u044b\u0435 \u0438\u0441\u0445\u043e\u0434\u044b).<\/em><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre><code>championships   id | country | gender |  league   |                      link ----+---------+--------+-----------+------------------------------------------------<\/code><\/pre>\n<pre><code>matches   match_id | league_id | match_date | start_time | team_home | team_away | league_name | stage | home_score | away_score | home_score_ft | away_score_ft | total_ft ----------+-----------+------------+------------+-----------+-----------+-------------+-------+------------+------------+---------------+---------------+----------<\/code><\/pre>\n<pre><code>details   match_id | home_q1 | away_q1 | home_q2 | away_q2 | home_q3 | away_q3 | home_q4 | away_q4 | home_ot | away_ot | home_win | away_win | total | handicap | hc_q1 ----------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+----------+----------+-------+----------+-------<\/code><\/pre>\n<h3>\u041d\u0430\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u21161<\/h3>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043f\u0435\u0440\u0432\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b &#8212; championships. <\/p>\n<p>\u041d\u0430 basketball24.com \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\u043e\u0432 \u0438\u0437 \u0432\u0441\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0441\u0442\u0440\u0430\u043d, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435  <\/p>\n<figure class=\"float\">\n<div><figcaption>\u041d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0424\u0440\u0430\u043d\u0446\u0438\u0438 \u044f \u0432\u043e\u0437\u044c\u043c\u0443 3 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\u0430 &#8212; \u041f\u0435\u0432\u0440\u0443\u044e \u0438 \u0412\u0442\u043e\u0440\u0443\u044e \u043b\u0438\u0433\u0443 \u0443 \u043c\u0443\u0436\u0447\u0438\u043d (LNB \u0438 Pro B), \u0438 \u041f\u0435\u0440\u0432\u0443\u044e \u043b\u0438\u0433\u0443 \u0443 \u0436\u0435\u043d\u0449\u0438\u043d (LFB Women)<\/figcaption><\/div>\n<\/figure>\n<p><\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u044f \u0443\u0432\u043b\u0435\u043a\u0441\u044f \u0438 \u043d\u0430\u0441\u043e\u0431\u0438\u0440\u0430\u043b 101 \u043c\u0443\u0436\u0441\u043a\u043e\u0439 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442 \u0438 48 \u0436\u0435\u043d\u0441\u043a\u0438\u0445. \u042d\u0442\u043e \u043f\u0435\u0440\u0432\u044b\u0435 \u0438 \u0432\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043b\u0438\u0433\u0438 \u0438 \u0435\u0432\u0440\u043e\u043f\u0435\u0439\u0441\u043a\u0438\u0435 \u043c\u0435\u0436\u043a\u043b\u0443\u0431\u043d\u044b\u0435 \u043f\u0435\u0440\u0432\u0435\u043d\u0441\u0442\u0432\u0430. \u042f \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043b \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442 \u0438 \u043f\u043e\u043b\u043e\u0436\u0438\u043b \u0432 \u0432\u0438\u0434\u0435 \u0434\u0432\u0443\u0445 \u0441\u043f\u0438\u0441\u043a\u043e\u0432: \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043c\u0443\u0436\u0441\u043a\u0438\u0445 \u0438 \u0436\u0435\u043d\u0441\u043a\u0438\u0445  <\/p>\n<pre><code>#bb_links.py  links_men = [     'https:\/\/www.basketball24.com\/albania\/superliga\/#\/QyhUb9xl\/table\/overall',     'https:\/\/www.basketball24.com\/argentina\/liga-a\/#\/KbRL3M3T\/table\/overall',     'https:\/\/www.basketball24.com\/australia\/nbl\/#\/YZEnCJej\/table\/overall',     ... ]  links_women = [     'https:\/\/www.basketball24.com\/argentina\/liga-femenina-women\/#\/UgCeKslA\/draw',     'https:\/\/www.basketball24.com\/australia\/wnbl-women\/#\/IBGTDowC\/table\/overall',     'https:\/\/www.basketball24.com\/austria\/superliga-women\/#\/Sx8xPi88\/table\/overall',     ... ]<\/code><\/pre>\n<p>\u0424\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0441 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u0434\u043e\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u0432\u0441\u044f\u043a\u0443\u044e \u0435\u0440\u0443\u0434\u043d\u0443 (\u043f\u043e \u0442\u0438\u043f\u0443 \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u043e\u0432, \u0432\u0440\u043e\u0434\u0435 &#171;#\/Sx8xPi88\/table\/overall&#187;) &#8212; \u043d\u0438\u0447\u0435\u0433\u043e \u0441\u0442\u0440\u0430\u0448\u043d\u043e\u0433\u043e, \u043f\u043e\u0442\u043e\u043c \u044d\u0442\u043e \u0434\u0435\u043b\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u043c.<\/p>\n<p>\u041c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u043f\u0435\u0440\u0432\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b championships:<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\u0442\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u0442\u044c) \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<br \/>.<br \/> \u251c\u2500\u2500 <a href=\"http:\/\/championships.py\" rel=\"noopener noreferrer nofollow\">championships.py<\/a><br \/> \u251c\u2500\u2500 link_collector.py<br \/> \u251c\u2500\u2500 main_run.py<br \/> \u251c\u2500\u2500 failed_run.py<br \/> \u251c\u2500\u2500 details<br \/> \u2502   \u251c\u2500\u2500 all_champs.json<br \/> \u2502   \u251c\u2500\u2500 bb_links.py<br \/> \u2502   \u2514\u2500\u2500 main_selectors.py<br \/> \u2502   \u251c\u2500\u2500 txt_links<br \/> \u2502   \u2502   \u2514\u2500\u2500 austria-superliga.txt<br \/> \u2502   \u2502   \u2514\u2500\u2500 failed<br \/> \u2502   \u2502       \u2514\u2500\u2500 japan-b-league.txt<br \/> \u251c\u2500\u2500 sport_handlers<br \/> \u2502   \u251c\u2500\u2500 basketball_handler.py<br \/> \u2502   \u2514\u2500\u2500 main_handler.py<br \/> \u2514\u2500\u2500 tests<br \/>      \u251c\u2500\u2500 test_leagues_actuality.py<br \/>      \u2514\u2500\u2500 test_slector_validity.py<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043a\u043e\u043c\u0443-\u0442\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0432\u0441\u044e \u0440\u0435\u043f\u0443 &#8212; <a href=\"https:\/\/github.com\/DenisLet\/SportDB\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>.<\/p>\n<pre><code class=\"python\">#championships.py  import os import json import psycopg2 from .details.bb_links import links_men, links_women  '''    Class create json and sql table with basketball     championships(and link for them to basketball24.com      choosen by yourself manually before '''   class Championships:      def __init__(self, sport=None):         self.all_leagues = {}         self.sport = sport         print(self.sport)      def add_league(self, data, gender):         for l in data:             country = l.split('\/')[3].replace('-', ' ').title()             league = l.split('\/')[4].replace('-', ' ').upper()             link = 'https:\/' + '\/'.join(l.split('\/')[1:5])              if country not in self.all_leagues:                 self.all_leagues[country] = {'Men': {}, 'Women': {}}              if league not in self.all_leagues[country][gender]:                 self.all_leagues[country][gender][league] = link      def process_data(self, data_men, data_women):         self.add_league(data_men, 'Men')         self.add_league(data_women, 'Women')      def save_to_json(self, filename='all_champs.json'):         folder_path = 'details'         file_path = os.path.join(folder_path, filename)         json_data = json.dumps(self.all_leagues, indent=4)         with open(file_path, 'w') as file:             file.write(json_data)       def connect_to_db(self, dbname):         return psycopg2.connect(             host=\"127.0.0.1\",             user=\"postgres\",             password=\"123456er\",             port=\"5432\",             dbname=dbname         )      def create_postgresql_db(self, dbname):         conn = self.connect_to_db(dbname)         cur = conn.cursor()          # \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 - \u0435\u0441\u0442\u044c \u0431\u0430\u0437\u0430 \u0438\u043b\u0438 \u043d\u0435\u0442         cur.execute(f\"SELECT 1 FROM pg_catalog.pg_database WHERE datname = '{dbname}'\")         database_exists = cur.fetchone()          # \u0415\u0441\u043b\u0438 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0435\u0442, \u0441\u043e\u0437\u0434\u0430\u044e \u043d\u043e\u0432\u0443\u044e         if not database_exists:             cur.execute(f\"CREATE DATABASE {dbname}\")             print(f\"Database '{dbname}' created successfully\")          conn.close()          # \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e\u0441\u044c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0439 \u0438\u043b\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0431\u0430\u0437\u0435         conn = self.connect_to_db(dbname)         cur = conn.cursor()          # \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 \u0431\u0430\u0437\u0435         cur.execute(\"SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'championships')\")         table_exists = cur.fetchone()[0]          # \u0415\u0441\u043b\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043d\u0435\u0442, \u0441\u043e\u0437\u0434\u0430\u044e \u043d\u043e\u0432\u0443\u044e         if not table_exists:             create_table_query = '''                 CREATE TABLE championships (                     id SERIAL PRIMARY KEY,                     country VARCHAR(100),                     gender VARCHAR(10),                     league VARCHAR(100),                     link VARCHAR(255),                     CONSTRAINT unique_country_gender_league UNIQUE (country, gender, league)                 )             '''             cur.execute(create_table_query)             conn.commit()             print(\"Table created successfully\")           for country, genders in self.all_leagues.items():             for gender, leagues in genders.items():                 for league, link in leagues.items():                     insert_query = f'''                         INSERT INTO championships (country, gender, league, link)                          VALUES ('{country}', '{gender}', '{league}', '{link}')                         ON CONFLICT (country, gender, league) DO NOTHING                     '''                     cur.execute(insert_query)                     conn.commit()          conn.close()  championships = Championships() championships.process_data(links_men, links_women) championships.save_to_json() championships.create_postgresql_db(dbname=\"sportdb\")<\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043c\u043e\u0434\u0443\u043b\u0435 \u043e\u0434\u0438\u043d \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u0437\u0432\u0430\u043d \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432\u0441\u0435 \u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0440\u0443\u043a\u0430\u043c\u0438 \u0441\u0441\u044b\u043b\u043a\u0438, \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0438\u0445 \u043f\u043e \u0447\u0435\u043c\u043f\u0438\u043e\u043d\u0430\u0442\u0430\u043c, \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 JSON (\u043e\u043d \u043f\u0440\u0438\u0433\u043e\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0438\u043d\u043e\u0433\u0434\u0430 \u043f\u043e\u0434\u0435\u0440\u0433\u0430\u0442\u044c \u043b\u0438\u043d\u043a\u0438 \u0432\u0440\u0443\u0447\u043d\u0443\u044e) \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c (\u0435\u0441\u043b\u0438 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0437\u0430\u0440\u0430\u043d\u0435\u0435) \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 sportdb, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 championships (\u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0437\u0430\u043a\u043e\u043b\u0445\u043e\u0437\u0438\u0442\u044c \u0442\u0440\u043e\u0435\u043a\u0440\u0430\u0442\u043d\u044b\u043c for, \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439 \u043c\u0430\u043b\u043e &#8212; \u0442\u0430\u043a \u0447\u0442\u043e \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e).  <\/p>\n<p>\u0412\u044b\u0448\u043b\u043e \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u043f\u043e 35<\/figcaption><\/div>\n<\/figure>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-367476","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/367476","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=367476"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/367476\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=367476"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=367476"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=367476"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}