Maison > Article > développement back-end > Utilisez un robot d'exploration multithread pour capturer l'e-mail et le numéro de téléphone mobile dans *
Ce robot explore principalement le contenu de diverses publications dans Baidu Tieba et analyse le contenu des publications pour extraire les numéros de téléphone mobile et les adresses e-mail. Le flux principal est expliqué en détail dans les commentaires du code.
Environnement de test :
Le code a été testé dans l'environnement Windows7 64 bits, python 2.7 64 bits (extension mysqldb installée) et centos 6.5, python 2.7 (avec extension mysqldb) et a réussi
Préparation de l'environnement :
Si vous voulez bien faire votre travail, vous devez d'abord affûter vos outils. Vous pouvez le voir sur la capture d'écran. que mon environnement est Windows 7 PyCharm . L'environnement Python est Python 2.7 64 bits. Il s'agit d'un environnement de développement plus adapté aux novices. Ensuite, je vous suggère d'installer un easy_install. Comme son nom l'indique, il s'agit d'un programme d'installation. Par exemple, si nous voulons faire fonctionner la base de données mysql en python, python ne le prend pas en charge nativement. . Nous devons installer le package mysqldb pour permettre à python de faire fonctionner la base de données mysql. S'il existe easy_install, nous n'avons besoin que d'une seule ligne de commandes pour installer rapidement le package d'extension mysqldb. C'est aussi pratique que composer en php, yum en centos. apt-get dans Ubuntu.
Les outils pertinents peuvent être trouvés sur github : cw1997/python-tools. Pour installer easy_install, il vous suffit d'exécuter le script py sous la ligne de commande python et d'attendre un moment. Il ajoutera automatiquement l'environnement Windows. variables , si vous entrez easy_install sur la ligne de commande Windows et qu'il y a un écho, cela signifie que l'installation est réussie.
Détails de la sélection de l'environnement :
En ce qui concerne le matériel informatique, bien sûr, plus il est rapide, mieux c'est, en commençant avec au moins 8 Go de mémoire, car le robot lui-même doit stocker et analyser une grande quantité de données intermédiaires, en particulier les robots d'exploration multithread. Lors de l'exploration de listes et de pages de détails avec pagination et que la quantité de données à analyser est importante, l'utilisation de la file d'attente pour allouer les tâches d'exploration occupera beaucoup de mémoire. Y compris parfois, les données que nous capturons utilisent json. Si elles sont stockées dans une base de données nosql telle que mongodb, elles prendront également beaucoup de mémoire.
Il est recommandé d'utiliser un réseau filaire pour la connexion réseau, car certains routeurs sans fil de qualité inférieure et cartes réseau sans fil civiles ordinaires sur le marché connaîtront des déconnexions de réseau intermittentes, des pertes de données, des pertes de paquets, etc. ouvert relativement grand.
En ce qui concerne le système d'exploitation et Python, choisissez bien sûr 64 bits. Si vous utilisez un système d'exploitation 32 bits, vous ne pouvez pas utiliser une grande mémoire. Si vous utilisez Python 32 bits, vous ne remarquerez peut-être aucun problème lors de la capture de données à petite échelle, mais lorsque la quantité de données devient importante, comme une liste, une file d'attente ou un dictionnaire stockant une grande quantité de données, cela le fera. cause Lorsque l'utilisation de la mémoire de Python dépasse 2 Go, une erreur de dépassement de mémoire sera signalée.
Si vous envisagez d'utiliser MySQL pour stocker des données, il est recommandé d'utiliser mysql5.5 et les versions ultérieures, car la version mysql5.5 prend en charge le type de données json, vous pouvez donc abandonner mongodb.
Quant à python, la version 3.x est désormais disponible, pourquoi python2.7 est-il toujours utilisé ici ? La raison pour laquelle j'ai choisi la version 2.7 est que le livre de programmation de base Python que j'ai acheté il y a longtemps est la deuxième édition et utilise toujours la version 2.7 comme exemple de version. Et il existe encore de nombreux didacticiels sur Internet qui utilisent la version 2.7, car la version 2.7 est encore très différente de la 3.x à certains égards. Si nous n'avons pas étudié la version 2.7, nous ne comprendrons peut-être pas certaines différences subtiles de syntaxe qui en résulteront. Il y a un écart dans notre compréhension ou nous ne pouvons pas comprendre le code de démonstration. Et il existe encore des packages dépendants qui ne sont compatibles qu'avec la version 2.7. Ma suggestion est que si vous êtes désireux d'apprendre Python et que vous travaillez ensuite dans une entreprise, et que l'entreprise n'a pas d'ancien code à maintenir, vous pouvez envisager de démarrer 3.x directement si vous avez beaucoup de temps et n'en avez pas. expert très systématique, juste Si vous pouvez vous appuyer sur des articles de blog dispersés sur Internet pour apprendre, alors il est préférable d'apprendre d'abord 2.7, puis 3.x. Après tout, vous pouvez démarrer avec 3.x rapidement après avoir appris 2.7.
Points de connaissances impliqués dans les robots multithread :
En fait, pour tout projet logiciel, si on veut savoir quels points de connaissances sont nécessaires pour écrire ce projet, on peut observer les points principaux de ce projet Quels packages sont importés dans le fichier d'entrée.
Jetons maintenant un coup d'œil à notre projet. En tant que personne novice en python, il se peut que certains packages n'aient presque jamais été utilisés. Donc, dans cette section, nous parlerons brièvement des fonctions de ces packages et comprendrons. leurs différences. Quels points de connaissance seront impliqués et quels sont les mots-clés de ces points de connaissance. Cet article ne prendra pas longtemps pour partir des bases, nous devons donc apprendre à faire bon usage de Baidu et rechercher des mots-clés pour ces points de connaissances afin de nous éduquer. Analysons ces points de connaissance un par un.
Protocole HTTP :
Essentiellement, notre robot d'exploration capture des données en lançant continuellement des requêtes http, en obtenant des réponses http et en les stockant dans notre ordinateur. Comprendre le protocole http nous aide à contrôler avec précision certains paramètres qui peuvent accélérer l'exploration lors de l'exploration des données, tels que le maintien de la vie, etc.
Module de thread (multi-threading) :
Les programmes que nous écrivons habituellement sont des programmes monothread. Les codes que nous écrivons s'exécutent tous dans le thread principal, et ce thread principal s'exécute dans le python. processus .
Le multi-threading est implémenté en python via un module appelé threading. Il y avait aussi le module thread auparavant, mais le threading a un contrôle plus fort sur les threads, nous sommes donc passés plus tard au threading pour implémenter la programmation multithread.
Pour faire simple, utiliser le module threading pour écrire un programme multi-thread c'est d'abord définir soi-même une classe, ensuite cette classe doit hériter du threading.Thread, et écrire le code de travail à faire par chacun thread dans l'exécution d'une méthode de classe, bien sûr, si le thread lui-même doit effectuer un travail d'initialisation lors de sa création, alors le code à exécuter pour le travail d'initialisation doit être écrit dans sa méthode __init__. la méthode constructeur en PHP et Java .
Un point supplémentaire à aborder ici est le concept de sécurité des threads. Normalement, dans notre situation monothread, un seul thread opère sur les ressources (fichiers, variables) à chaque instant, il est donc peu probable qu'il y ait des conflits. Cependant, dans le cas du multithreading, deux threads peuvent exploiter la même ressource en même temps, provoquant des dommages aux ressources. Par conséquent, nous avons besoin d'un mécanisme pour résoudre les dommages causés par ce conflit, qui implique généralement un verrouillage et d'autres opérations. Par exemple, le moteur de table innodb de la base de données mysql a des verrous au niveau des lignes, etc., et les opérations sur les fichiers ont des verrous en lecture, etc. Tout cela est complété pour nous par la couche inférieure de leur programme. Nous avons donc généralement seulement besoin de connaître ces opérations ou ces programmes qui traitent des problèmes de sécurité des threads, puis nous pouvons les utiliser dans une programmation multithread. Ce type de programme qui prend en compte les problèmes de sécurité des threads est généralement appelé « version de sécurité des threads ». Par exemple, PHP a une version TS, et ce TS signifie Thread Safety. Le module Queue dont nous allons parler ci-dessous est une structure de données de file d'attente thread-safe, nous pouvons donc l'utiliser en programmation multithread en toute confiance.
Enfin nous parlerons du concept crucial du blocage des threads. Après avoir étudié en détail le module de threading, nous saurons probablement comment créer et démarrer des threads. Mais si nous créons le thread et appelons ensuite la méthode start, nous constaterons que le programme entier se termine immédiatement. Que se passe-t-il ? En fait, c'est parce que nous n'avons que le code chargé de démarrer le sous-thread dans le thread principal, ce qui signifie que le thread principal n'a que pour fonction de démarrer le sous-thread Quant aux codes exécutés par le sous-thread. , il s'agit essentiellement d'une méthode écrite dans la classe. Elle n'est pas réellement exécutée dans le thread principal, donc une fois que le thread principal a démarré le sous-thread, tout son travail est terminé et il s'est terminé glorieusement. Maintenant que le thread principal est terminé, le processus Python se terminera et les autres threads n'auront plus d'espace mémoire pour continuer l'exécution. Nous devrions donc laisser le frère du thread principal attendre que tous les frères du sous-thread aient fini de s'exécuter avant de quitter glorieusement. Existe-t-il donc une méthode dans l'objet thread pour bloquer le thread principal ? fil.sommeil ? C'est effectivement une solution, mais combien de temps le thread principal doit-il dormir ? Nous ne savons pas exactement combien de temps il faudra pour accomplir une tâche, nous ne pouvons donc certainement pas utiliser cette méthode. Donc, à ce moment-là, nous devrions vérifier en ligne s'il existe un moyen de "bloquer" le sous-thread dans le thread principal ? Le mot "bloqué" semble trop vulgaire. En fait, pour être plus professionnel, il devrait s'appeler "blocage", afin que l'on puisse interroger "le sous-thread python bloque le thread principal". trouver une méthode. Elle s'appelle join(). Oui, cette méthode join() est la méthode utilisée par le sous-thread pour bloquer le thread principal. Lorsque le sous-thread n'a pas fini de s'exécuter, le thread principal reste bloqué lorsqu'il est exécuté. atteint la ligne contenant la méthode join(). Là, le code suivant la méthode join() ne sera pas exécuté tant que tous les threads n'auront pas fini de s'exécuter.
Module de file d'attente (file d'attente) :
Supposons qu'il y ait un scénario dans lequel nous devons explorer le blog d'une personne. Nous savons que le blog de cette personne a deux pages, une page list.php Tous les liens vers les articles. de ce blog sont affichés, et il y a aussi une page view.php qui affiche le contenu spécifique d'un article.
Si nous voulons explorer tout le contenu de l'article dans le blog de cette personne, l'idée d'écrire un robot d'exploration à thread unique est la suivante : utilisez d'abord des expressions régulières pour explorer l'attribut href de la balise a de tous les liens de ce blog. page list.php. Stockez un tableau nommé article_list (pas appelé tableau en Python, cela s'appelle une liste, une liste de noms chinois), puis utilisez une boucle for pour parcourir le tableau article_list, utilisez diverses fonctions pour capturer le contenu de la page Web. , puis récupérez le contenu dans la base de données.
Si nous voulons écrire un robot d'exploration multithread pour accomplir cette tâche, en supposant que notre programme utilise 10 threads, nous devons alors trouver un moyen de diviser la liste d'articles précédemment analysée en 10 parties, respectivement. est affecté à l’un des threads enfants.
Mais voici le problème. Si la longueur de notre tableau article_list n'est pas un multiple de 10, c'est-à-dire que le nombre d'articles n'est pas un multiple entier de 10, alors le dernier fil se verra attribuer moins de tâches. que les autres discussions, alors ce sera fini plus tôt.
Si nous explorons simplement ce genre d'article de blog avec seulement quelques milliers de mots, cela ne semble poser aucun problème, mais si nous avons une tâche (pas nécessairement la tâche d'explorer des pages Web, il peut s'agir de calculs mathématiques , ou rendu graphique Si le temps d'exécution des tâches chronophages (telles que les tâches chronophages) est très long, cela entraînera une énorme perte de ressources et de temps. Notre objectif du multithreading est d'utiliser autant que possible toutes les ressources informatiques et le temps de calcul, nous devons donc trouver des moyens de répartir les tâches de manière plus scientifique et rationnelle.
Et nous devons également considérer une situation, c'est-à-dire que lorsque le nombre d'articles est important, nous devons pouvoir explorer rapidement le contenu de l'article et voir le contenu que nous avons exploré dès que possible La demande se reflète souvent sur de nombreux sites de collecte de CMS.
Par exemple, le blog cible que nous voulons explorer compte désormais des dizaines de millions d'articles. Dans ce cas, le blog sera généralement paginé, donc si nous suivons l'idée traditionnelle ci-dessus et explorons d'abord list.php. les pages prendront au moins plusieurs heures, voire plusieurs jours. Si le patron espère que vous pourrez afficher le contenu exploré le plus rapidement possible et afficher le contenu exploré sur notre station de collecte CMS le plus rapidement possible, alors nous devons mettre en œuvre une exploration simultanée. .php et jetez les données capturées dans un tableau article_list. En même temps, utilisez un autre fil pour extraire l'adresse URL de l'article qui a été capturée du tableau article_list. Ensuite, ce fil utilisera des expressions régulières dans l'adresse URL correspondante. Obtenez le contenu de l'article de blog. Comment implémenter cette fonction ?
Nous devons ouvrir deux types de fils de discussion en même temps. Un type de fil de discussion est spécifiquement responsable de la récupération de l'URL dans list.php et de son lancement dans le tableau article_list. pour extraire l'URL de article_list, puis l'extraire du correspondant. Capturez le contenu du blog correspondant à partir de la page view.php.
Mais est-ce qu'on se souvient encore du concept de thread safety évoqué plus haut ? Le premier type de thread écrit les données dans le tableau article_list et l'autre type de thread lit les données de article_list et supprime les données qui ont été lues. Cependant, list en python n'est pas une version thread-safe de la structure de données, cette opération provoquera donc des erreurs imprévisibles. Nous pouvons donc essayer d'utiliser une structure de données plus pratique et plus sûre pour les threads, qui est la structure de données de file d'attente mentionnée dans notre sous-titre.
De même, Queue a également une méthode join(). Cette méthode join() est en fait similaire à la méthode join() dans le threading mentionnée dans la section précédente, sauf que dans Queue, la condition de blocage de join( ) est Block uniquement lorsque la file d'attente n'est pas vide, sinon continuez à exécuter le code après join(). Dans ce robot, j'ai utilisé cette méthode pour bloquer le thread principal au lieu de bloquer le thread principal directement via la méthode join du thread. L'avantage est que je n'ai pas besoin d'écrire une boucle infinie pour déterminer s'il y en a encore. tâches inachevées dans la file d'attente des tâches actuelle, ce qui rend le programme plus efficace et le code plus élégant.
Un autre détail est que le nom du module de file d'attente en python2.7 est Queue, mais il a été renommé queue en python3. Rappelez-vous cette petite différence.
module getopt :
Si vous avez appris le langage C, vous devez être familier avec ce module. C'est un module chargé d'extraire les paramètres attachés de la commande sur la ligne de commande. Par exemple, lorsque nous exploitons habituellement la base de données mysql sur la ligne de commande, nous entrons mysql -h127.0.0.1 -uroot -p, où "-h127.0.0.1 -uroot -p" après mysql est la partie paramètre qui peut être obtenu.
Lorsque nous écrivons habituellement des robots d'exploration, certains paramètres doivent être saisis manuellement par l'utilisateur, tels que l'adresse IP de l'hôte MySQL, le nom d'utilisateur et le mot de passe, etc. Afin de rendre notre programme plus convivial et polyvalent, certains éléments de configuration n'ont pas besoin d'être codés en dur dans le code, mais nous les transmettons dynamiquement lors de leur exécution. En les combinant avec le module getopt, nous pouvons réaliser cette fonction.
hashlib (hachage) :
Le hachage est essentiellement un ensemble d'algorithmes mathématiques. Une caractéristique de cet algorithme mathématique est que si vous donnez un paramètre, il peut produire un autre résultat. Bien que ce résultat soit très court, il peut être considéré comme unique. Par exemple, on entend généralement md5, sha-1, etc., ils appartiennent tous à des algorithmes de hachage. Ils peuvent convertir certains documents et textes en une chaîne de chiffres et d'anglais mélangés de moins d'une centaine de chiffres après une série d'opérations mathématiques.
Le module hashlib en python encapsule pour nous ces fonctions d'opération mathématique. Il nous suffit de l'appeler pour terminer l'opération de hachage.
Pourquoi dois-je utiliser ce package dans mon robot ? Car dans certaines requêtes d'interface, le serveur doit apporter des codes de vérification pour s'assurer que les données demandées par l'interface n'ont pas été falsifiées ou perdues. Ces codes de vérification sont généralement des algorithmes de hachage, nous devons donc utiliser ce module pour réaliser cette opération. .
json :
Souvent, les données que nous capturons ne sont pas du HTML, mais certaines données json sont essentiellement une chaîne contenant des paires clé-valeur si nous devons l'extraire. , nous avons alors besoin du module json pour convertir cette chaîne json en un type dict pour notre opération.
re (expression régulière) :
Parfois, nous capturons du contenu Web, mais nous devons extraire du contenu dans un format spécifique de la page Web, comme le courrier électronique. Le format est généralement le premier quelques lettres anglaises plus un symbole @ plus le nom de domaine http://xxx.xxx Pour décrire ce format dans un langage informatique, nous pouvons utiliser une expression appelée expression régulière pour exprimer Ce format permet à l'ordinateur de faire correspondre automatiquement le texte qui. est conforme à ce format spécifique à partir d'une grande chaîne.
sys :
Ce module est principalement utilisé pour gérer certains problèmes système. Dans ce robot, je l'utilise pour résoudre le problème d'encodage de sortie.
heure :
Quiconque a appris un peu d'anglais peut deviner que ce module est utilisé pour traiter l'heure dans ce robot, je l'utilise pour obtenir l'horodatage actuel, puis je passe. sur le thread principal À la fin, soustrayez l'horodatage du début de l'exécution du programme de l'horodatage actuel pour obtenir la durée d'exécution du programme.
Comme le montre l'image, ouvrez 50 fils de discussion pour explorer 100 pages (30 messages par page, équivalent à explorer 3000 messages) et extraire le contenu des messages Tieba. Cette étape de l'accès à la boîte aux lettres mobile a pris au total 330 secondes.
urllib et urllib2 :
Ces deux modules sont utilisés pour gérer certaines requêtes http et le formatage des url. Le code principal de la partie requête http de mon robot est complété à l'aide de ce module.
MySQLdb :
Il s'agit d'un module tiers permettant d'exploiter la base de données MySQL en python.
Ici, nous devons faire attention à un détail : le module mysqldb n'est pas une version thread-safe, ce qui signifie que nous ne pouvons pas partager le même handle de connexion mysql dans plusieurs threads. Vous pouvez donc voir dans mon code que je passe un nouveau handle de connexion MySQL dans le constructeur de chaque thread. Par conséquent, chaque thread enfant utilisera uniquement son propre handle de connexion MySQL indépendant.
cmd_color_printers :
Il s'agit également d'un module tiers, et le code correspondant peut être trouvé en ligne. Ce module est principalement utilisé pour afficher des chaînes de couleurs sur la ligne de commande. Par exemple, lorsque nous avons généralement une erreur dans le robot d'exploration, si nous voulons afficher des polices rouges qui seront plus visibles, nous devons utiliser ce module.
Gestion automatisée des erreurs du robot :
Si vous utilisez ce robot dans un environnement où la qualité du réseau n'est pas très bonne, vous constaterez que parfois il le fera signalez ce qui suit : Pour l'exception illustrée dans la figure, aucune gestion des exceptions n'est écrite ici.
Normalement, si nous voulons écrire un robot hautement automatisé, nous devons anticiper toutes les situations anormales que notre robot peut rencontrer et gérer ces situations anormales.
Par exemple, s'il y a une erreur comme indiqué sur l'image, nous devons réinsérer la tâche en cours de traitement à ce moment-là dans la file d'attente des tâches, sinon nous manquerons des informations. C'est également un point compliqué dans l'écriture des robots.