Scraping - Python + BeautifulSoup + Mechanize

Bonjour à toute la communauté !

Je vous contacte aujourd’hui car je suis bloqué sur un programme en Python qui a pour but d’envoyer en masse un message à tous les membres d’un plateforme.

Je précise que je viens de démarrer il y a 3 jours sur Python et que je reste novice sur tout ce que m’offre Python et ses différents librairies de scraping :grinning:

A ce jour l’algorithme est finalisé ainsi que le code, par contre je me heurte à un souci que je n’arrive pas à résoudre : la connexion sur le site pour envoyer des messages.

Ci-dessous voici un extrait des champs que je dois remplir pour m’identifier (j’ai un compte sur cette plateforme ) :

Voici une partie du code qui me permet de soumettre mes informations de connexion :

Mon problème est le suivant : les noms des champs que je spécifie ne sont apparemment pas reconnus et je ne comprends pas pourquoi. J’ai utilisé pas mal de print pour débugguer mon souci et je n’ai pas la réponse.

Voici un extrait du log :

Ainsi que de l’erreur :

Si quelqu’un à une idée pour m’aider à comprendre pourquoi les noms des login & mot de passe que je lui fournis ne sont pas reconnus je suis preneur :grinning:

Peut être il y a une manière plus simple d’émuler mon propre navigateur où je suis connecté ? Ou alors je me trompe totalement sur l’approche ?

Merci d’avance pour votre aide précieuse ! :sunglasses:

Hey,

Que se passe t-il lorsque tu écris ce code:

emailControl = br.form.find_control("data[User][email]")
passwordControl = br.form.find_control("data[User][password]")
emailControl.value = "monadresseemail"
passwordControl.value = "monmotdepasse"
1 J'aime

Hello ! Merci pour ta réponse :grinning:

Je viens de faire l’essaie avec ce que tu m’as fourni, voici le résultat :

Le code retourne une erreur sur la premier ligne car il ne trouve pas « data[User][email] ».

Je peux si tu le souhaites t’envoyer la page en MP ? Pour faire « simple » :

  • J’arrive sur la page pour envoyer le message
  • Un pop s’ouvre me demande de rentrer mes informations de connexion.

Je pense avoir une piste qui expliquerait pourquoi on ne trouve rien : J’ai utilisé les lignes de codes suivantes (la fonction goto_url que j’ai créé me permet de construire l’url en fonction du profil de chaque utilisateur. En gros c’est mon url de base + une url custom propre à chaque utilisateur) :

resp_msgPage = requests.get(goto_url(root_url, word_profile,’’ ))
soup_msgPage = BeautifulSoup(resp_msgPage.text, ‹ lxml ›)
print(soup_msgPage)

Le retour me donne le code de la page « derrière » et non celui de la pop-up, d’où l’explication qu’il ne trouve pas les champs.

Il faudrait peut être que je connecte dès le début du code pour m’éviter ce problème ?
J’ai vu que certaines personnes passaient par import « http.cookiejar as cookielib » mais je n’ai pas bien compris encore le fonctionnement.

Hello de nouveau !

Après m’être cassé les dents pendant plusieurs heures pour comprendre mon problème je viens enfin de trouver :innocent:

J’ai créé une fonction d’initialisation où je déclare un browser que je vais réutiliser tout le long de mes fonctions.
Il m’a fallu ensuite créer une fonction de connexion que je déclare et j’utilise dans cette fonction d’initialisation.
Pour accéder aux Controls que je souhaitais, je suis passé par leurs indices que j’ai trouvé ici :

print (br.form.controls[0]) # _method=POST)
print (br.form.controls[1]) # data[_Token][key]
print (br.form.controls[2]) # email
print (br.form.controls[3]) # password

Il ne m’a plus resté qu’à leur définir une valeur comme cela :

br.form.set_value(« monmail », nr=2) # email
br.form.set_value(« monmotdepasse », nr=3) # password

Puis je soumets et le tour est joué pour l’authentification :

br.method = « POST »
response = br.submit()

Je n’avais plus qu’à utiliser le Browser précédemment défini dans le reste de mon code et magie : plus besoin d’authentification nul part :grinning:

Concernant l’envoi des messages, je suis passé par la même méthode :

br.form.set_value(title, nr=2) # title of the message
br.form.set_value(message, nr=3) # content of the message

Dernier chantier : enregistrer dans un txt ou un CSV les profils à qui j’aurai envoyé un message pour ne pas me retaper les 2500 pages de profil si jamais la fonction plante :grinning:

Je ne sais pas si ma méthode est orthodoxe mais je suis plutôt fier de moi après mon 4ème jour de développement sur Python ^^

PS : pour ceux qui en aurait besoin je pourrais vous conseiller des cours sur Udemy ou des livres que j’ai acheté sur Kindle pour comprendre les subtilités de Python & BeautifulSoup. Je suis loin d’être expert mais ils m’ont bien aidé.

Dernière question : me conseillez-vous d’écrire plutôt dans un txt ou directement dans un CSV ? (ou autre chose) Je ne sais pas s’il y a des différences notables en performance. Merci à tous !

2 J'aimes

Hello SMNY,
je suis preneur sur la référence des cours et documentation.
Apprendre à coder en Python c’est ma bonne résolution de l’année2020

Hello !
Belle résolution :slight_smile: Je commence à être plutôt très autonome et je finirai presque par adorer Python !

Donne moi ton adresse email en MP car je n’ai que le pdf et je ne trouve plus l’url d’un des tops ebooks que j’ai récupéré… :slight_smile:

Sinon j’ai ce lien qui est vraiment pas mal ==> https://inforef.be/swi/download/apprendre_python3_5.pdf

A ta dispo :slight_smile:

2 J'aimes

Salut les GH, je viens de me mettre aussi sur Python ça fait un bout de temps,
j’ai réussi à bricoler quelques utilitaires, mais je bute sur un truc.

J’essaie d’extraire les sites web des sociétés de prospects sur Linkedin, jusqu’ici l’algo est à 90% au point (Pour info j’utilise Selenium sur Python) voici le topo du script.

  • Le bot se connecte sur Linkedin.
  • Se rend sur le profil du prospect
  • Clique sur le logo de l’entreprise actuelle du prospect (ce qui l’amène vers la page de la société)
  • J’arrive à localiser le bouton « Voir le site web » et cliquer dessus, mais je n’arrive pas à extraire l’adresse du site web, le site s’ouvrant sur un nouvel onglet, sur lequel Selenium n’a pas la main, et j’ai essayé tout les sélecteurs possible je n’arrive pas à extraire l’adresse du site web, voici le code de la balise html :

image


Edit : J’ai trouvé la solution en utilisant l’xpath absolu, le problème venait de l’IDE Selenium qui donnait l’xpath de la balise enfant qui ne contient que le texte du bouton.
image

1 J'aime

Hello @Manfromtunis, pour éviter tout problème futur lié à d’éventuels changements de structure de la page, il faudrait que tu utilises un XPath simplifié et mettre de coté les XPath absolus.

Il suffit qu’ils rajoutent un div quelque part dans la hiérarchie de la page, et ton XPath actuel qui se trouve être à la fois un XPath absolu et « positionnel » ne matchera plus rien, car il est trop restrictif et trop « bancal ».

Un truc du genre pourrait être pas mal :slight_smile: :

//a[contains(@data-control-name, 'view_website')]/@href

Hello pour faire ça il suffit que tu loope dans ton fichier et que tu écrives à chaque fois :slight_smile: c’est pas très compliqué

Conseil pour le webscraping

  1. Utilise jupyter ce sera beaucoup plus simple de visualiser
  2. Utilise plutôt vscode ou pycharme

Voilà voilà si tu as besoin d aide n hésites pas

Hello @ScrapingExpert, merci pour le conseil,
J’avais fait ça au début, mais ça me donnait la balise enfant,
Donc je peux sélectionner avec le data-control-name. je suis encore nul avec le xpath :smiley:

En fait, si je peux être plus précis et qu’on découpe le XPath, on peut distinguer plusieurs parties dans ce XPath:

//a[contains(@data-control-name, 'view_website')]/@href
  • //a: Ici on utilise la notion d’« axe », on interroge l’arbre HTML afin de sélectionner tous les nœuds de type « balise a »
  • [contains(@data-control-name, 'view_website')]: ici on introduit une condition, qu’on appel aussi « prédicat », qui permet de filtrer les axes précédemment sélectionnés selon un critère précis. Ce critère de filtrage ici c’est "tous les noeuds sélectionnés possédant l’attribut data-control-name et pour lequel la valeur contient la chaine de caractère « view_website »
  • /@href: A partir des axes précédemment filtrés, on descend d’un niveau dans l’arbre pour sélectionner les nodes de type « attribut href »

:slight_smile:

@ScrapingExpert merci pour l’explication,
j’ai utilisé ton sélecteur, en changeant le data-control-name et en enlevant l’attribut href, pour le capturer dans une autre variable (ça n’a pas voulu marcher directement) et ça marche nickel !

thanks !