1818# Global variables
1919SCRIPT_NAME = 'CW Wizard'
2020
21- VERSION = '1.0.4 '
21+ VERSION = '1.0.5 '
2222
2323EXIT_ERROR_MSG = 'The Wizard encountered issue(s) please check previous logs.\n '
2424EXIT_SUCCESS_MSG = 'The Wizard has finish is work, have a great day!\n '
2525
2626# These two variables are extracted and set from the first wantlist url given to the script
27- CURR_LANG = 'en'
2827CURR_GAME = 'Magic'
2928
3029CARDMARKET_TOP_DOMAIN = '.cardmarket.com'
3130CARDMARKET_BASE_URL = 'https://www' + CARDMARKET_TOP_DOMAIN
3231CARDMARKET_BASE_URL_REGEX = r'^https:\/\/www\.cardmarket\.com'
3332
34- # This value can be overwriten via script arguments or via GUI
33+ # This value can be override via script arguments or via GUI
3534MAXIMUM_SELLERS = 20
3635
36+ # This value cannot be currently override (this represent a max of 300 offers per card)
37+ MAXIMUM_NB_REQUESTS_PER_CARD = 6
38+
3739CARD_LANGUAGES = { 'English' : 1 , 'French' : 2 , 'German' : 3 , 'Spanish' : 4 ,
3840 'Italian' : 5 , 'S-Chinese' : 6 , 'Japanese' : 7 ,
3941 'Portuguese' : 8 , 'Russian' : 9 , 'Korean' : 10 ,
@@ -229,11 +231,11 @@ def cardmarket_log_in(session, credentials, silently=False):
229231
230232 # Step 3: Prepare payload
231233 token = regex_match .group ('token' )
232- referal_page_path = '/{} /{}' .format (CURR_LANG , CURR_GAME )
234+ referal_page_path = '/en /{}' .format (CURR_GAME )
233235 payload = {'__cmtkn' : token , 'referalPage' : referal_page_path , 'username' : credentials ['login' ], 'userPassword' : credentials ['password' ]}
234236
235237 # Step 4: Do the log-in POST request to Cardmarket with the payload
236- response_post_login = session .post ('{}/{} /{}/PostGetAction/User_Login' .format (CARDMARKET_BASE_URL , CURR_LANG , CURR_GAME ), data = payload )
238+ response_post_login = session .post ('{}/en /{}/PostGetAction/User_Login' .format (CARDMARKET_BASE_URL , CURR_GAME ), data = payload )
237239 if response_post_login .status_code != 200 :
238240 # Issue with the request
239241 funct_result .addDetailedRequestError ('log-in to Cardmarket' , response_post_login )
@@ -258,7 +260,7 @@ def cardmarket_log_out(session, silently=False):
258260 if not silently :
259261 LOG .debug ('------- The Wizard log out of the temporary session on Cardmarket...\n ' )
260262
261- response_get_logout = session .get ('{}/{} /{}/PostGetAction/User_Logout' .format (CARDMARKET_BASE_URL , CURR_LANG , CURR_GAME ))
263+ response_get_logout = session .get ('{}/en /{}/PostGetAction/User_Logout' .format (CARDMARKET_BASE_URL , CURR_GAME ))
262264 if response_get_logout .status_code != 200 :
263265 # Issue with the request
264266 funct_result .addDetailedRequestError ('logout of Cardmarket' , response_get_logout )
@@ -318,6 +320,15 @@ def retrieve_wantlist(session, wantlist_url, continue_on_warning=False):
318320
319321 wantlist = None
320322
323+ # Get Information from url to recreate it (changing language to english)
324+ wantlist_url_regex = CARDMARKET_BASE_URL_REGEX + r"\/[a-z]{2}\/(?P<game>\w+)\/Wants/(?P<wantlist_id>\d+)$"
325+ match = re .match (wantlist_url_regex , wantlist_url )
326+ if not match :
327+ funct_result .addError ('The wantlist url ("{}") seems invalid' .format (wantlist_url ))
328+ return funct_result
329+
330+ wantlist_url = '{}/en/{}/Wants/{}' .format (CARDMARKET_BASE_URL , match .group ('game' ), match .group ('wantlist_id' ))
331+
321332 # Step 1: Get the desired wantlist page
322333 response_get_wantlist = session .get (wantlist_url )
323334 if response_get_wantlist .status_code != 200 :
@@ -409,6 +420,8 @@ def _get_load_more_request_token(load_more_btn):
409420
410421
411422def load_more_articles (session , funct_result , soup , card , articles_table ):
423+ nb_of_requests = 0
424+
412425 # Step 1: Check if there isn't a load more articles button, in this case we stop
413426 load_more_btn = soup .find (id = 'loadMoreButton' )
414427 if not load_more_btn :
@@ -422,7 +435,7 @@ def load_more_articles(session, funct_result, soup, card, articles_table):
422435 request_token = _get_load_more_request_token (load_more_btn )
423436
424437 # Step 3: Retrieve more article until card['maxPrice'] is reached or there is no more article to load
425- while active :
438+ while active and nb_of_requests < MAXIMUM_NB_REQUESTS_PER_CARD :
426439 # Step 3.A: Get the price of the last card currently displayed
427440 last_article = articles_table .contents [- 1 ]
428441 last_article_price_str = last_article .find ('div' , class_ = 'price-container' ).find ('span' , class_ = 'text-nowrap' ).contents [0 ]
@@ -433,7 +446,7 @@ def load_more_articles(session, funct_result, soup, card, articles_table):
433446 # Step 3.B.I: Initialize a payload and do a POST request
434447 args_base64 = base64 .b64encode (bytes (json .dumps (load_more_args , separators = (',' , ':' )), 'utf-8' ))
435448 payload = {'args' : request_token + args_base64 .decode ("utf-8" )}
436- response_post_load_article = session .post ('{}/{} /{}/AjaxAction' .format (CARDMARKET_BASE_URL , CURR_LANG , card_curr_game ), data = payload )
449+ response_post_load_article = session .post ('{}/en /{}/AjaxAction' .format (CARDMARKET_BASE_URL , card_curr_game ), data = payload )
437450 if response_post_load_article .status_code != 200 :
438451 # Issue with the request
439452 funct_result .addWarning ('Failed to load more articles for card page ("{}")' .format (card ['title' ]))
@@ -442,16 +455,27 @@ def load_more_articles(session, funct_result, soup, card, articles_table):
442455
443456 # Step 3.B.II: Handle the request result containing the new articles and the new page_index value
444457 more_article_soup = BeautifulSoup (response_post_load_article .text , 'html.parser' )
445- load_more_args ['page' ] = int (more_article_soup .find ('newpage' ).contents [0 ])
458+ new_page_index_soup = more_article_soup .find ('newpage' )
459+ if new_page_index_soup :
460+ load_more_args ['page' ] = int (new_page_index_soup .contents [0 ])
461+ new_articles_rows_soup = more_article_soup .find ('rows' )
462+ if new_articles_rows_soup :
463+ articles_rows_html_str = base64 .b64decode (new_articles_rows_soup .contents [0 ]).decode ("utf-8" )
464+ articles_table .append (BeautifulSoup (articles_rows_html_str , 'html.parser' ))
465+ else :
466+ active = False
446467
447- articles_rows_html_str = base64 .b64decode (more_article_soup .find ('rows' ).contents [0 ]).decode ("utf-8" )
448- articles_table .append (BeautifulSoup (articles_rows_html_str , 'html.parser' ))
449- if load_more_args ['page' ] < 0 :
450- # There is no more article available, stop the process
468+ # TODO: All these if else active = False should be refactored
469+ if load_more_args ['page' ] < 0 :
470+ # There is no more article available, stop the process
471+ active = False
472+ else :
451473 active = False
452474 else :
453475 active = False
454476
477+ nb_of_requests += 1
478+
455479
456480def populate_sellers_dict (session , sellers , wantlist , articles_comment = False , continue_on_warning = False ):
457481 funct_result = FunctResult ()
@@ -460,7 +484,7 @@ def populate_sellers_dict(session, sellers, wantlist, articles_comment=False, co
460484 LOG .debug (' |____ The Wizard is aggregating sellers and articles data for the wantlist ("{}")...' .format (wantlist_url ))
461485
462486 for card in wantlist :
463- # If multiple languages selected with do one request per language
487+ # If multiple languages selected, do one request per language
464488 for card_language in card ['languages' ]:
465489 # Save a sellers list for the current card,
466490 # to avoid adding multiple time the same article for a seller
@@ -494,7 +518,7 @@ def populate_sellers_dict(session, sellers, wantlist, articles_comment=False, co
494518 if isinstance (card ['maxPrice' ], Decimal ):
495519 load_more_articles (session , funct_result , soup , card , articles_table )
496520
497- # Step 4: Iterate over articles
521+ # Step 4: Iterate over articles (a.k.a offers)
498522 for article_row in articles_table .children :
499523 # Step 4.A: Check if this is a proper article
500524 if 'article-row' not in article_row .attrs ['class' ]:
@@ -857,9 +881,7 @@ def check_wantlists_and_max_sellers(wantlist_urls, max_sellers, silently=False):
857881 # Since new games can be added to Cardmarket, checking "global_game" is not worth it
858882
859883 # Step 4: Assign info to global variables
860- global CURR_LANG
861884 global CURR_GAME
862- CURR_LANG = global_language
863885 CURR_GAME = global_game
864886
865887 return funct_result
0 commit comments