Auparavant, nous écrivions des robots d'exploration, et le framework le plus utilisé était scrapy. Aujourd'hui, nous utilisons le nouveau framework de robot d'exploration feapder pour développer des robots d'exploration et voir de quel type d'expérience il s'agit.
Site Web cible: aHR0cHM6Ly93d3cubGFnb3UuY29tLw ==
Conditions requises: Collectez les listes de tâches et les détails des tâches, et les détails doivent être mis à jour tous les 7 jours.
À titre de démonstration, les éléments suivants ne recherchent que les messages liés aux robots d'exploration
1. Recherche
1.1 Page de liste
Tout d'abord, nous devons voir si la page est rendue dynamiquement et si l'interface est anti-escalade.
Pour voir s'il s'agit d'un rendu dynamique, vous pouvez cliquer avec le bouton droit de la souris pour afficher le code source de la page Web, puis rechercher l'existence du code source du contenu sur la page Web. Par exemple, si la première technologie Zhiyi de la liste de recherche correspond 0, il est initialement considéré comme un rendu dynamique
Ou vous pouvez utiliser la commande feapder pour télécharger le code source de la page Web et l'afficher.
La page ouverte est en cours de chargement
L'appel de la commande response.open () produira un fichier temp.html dans le répertoire de travail. Le contenu est le code source renvoyé par la requête en cours. Nous cliquons pour l'afficher. Il s'agit d'une section de js avec vérification de sécurité. Par conséquent, on peut en déduire que le site Web a un système anti-escalade et un avertissement précoce de la mise à niveau de difficulté
Feapder prend également en charge l'utilisation de la demande de commande curl, la manière est la suivante:
Appuyez sur F12 ou faites un clic droit pour vérifier, ouvrez la fenêtre de débogage, actualisez la page, cliquez sur la demande de la page actuelle, copiez-la en tant que curl, revenez à la fenêtre de ligne de commande, entrez dans le shell feapder - et collez le contenu qui vient d'être copié
On constate que le transport des en-têtes et des cookies n'est pas bon, peut-être que certains paramètres ne peuvent être utilisés qu'une seule fois.
Conclusion de la recherche: anti-escalade sur la page liste, rendu dynamique de la page
ps: Le dieu normal continuera à enquêter, quelle est l'interface de la liste, comment casser l'anti-crawl, mais parce que je suis un novice, je ne m'inquiéterai pas à ce sujet.
1.2 Page de détails
Semblable à l'enquête sur les pages de liste, la conclusion est qu'il existe un anti-crawl, mais la page n'est pas rendue dynamiquement
2. Créez le projet
Ouvrez l'outil de ligne de commande et entrez:
> feapder create -p lagou-spider
lagou-spider 项目生成成功
Le projet généré est le suivant:
J'utilise pycharm, clique d'abord avec le bouton droit de la souris et ajoute cet élément à l'espace de travail.
(Cliquez avec le bouton droit sur le nom du projet, Marquer le répertoire comme -> Racine des sources)
3. Rédigez un robot d'exploration de page de liste
3.1 Créer un robot d'exploration
> cd lagou-spider/spiders
> feapder create -s list_spider
ListSpider 生成成功
Le code généré est le suivant:
import feapder
class ListSpider(feapder.AirSpider):
def start_requests(self):
yield feapder.Request("https://www.baidu.com")
def parse(self, request, response):
print(response)
if __name__ == "__main__":
ListSpider().start()
Ceci est un exemple de demande de Baidu, qui peut être exécuté directement
3.2 Reptiles photo
Tâches d'émission:
def start_requests(self):
yield feapder.Request("https://www.lagou.com/jobs/list_%E7%88%AC%E8%99%AB?labelWords=&fromSearch=true&suginput=", render=True)
Notez que nous avons porté le paramètre de rendu dans la demande pour indiquer s'il faut utiliser le navigateur pour effectuer le rendu, car cette page de liste est rendue dynamiquement, et il y a un anti-crawl, je suis plutôt confus, j'ai donc utilisé le mode de rendu pour éviter la perte de cheveux
Ecrire des fonctions analytiques
Observez la structure de la page et écrivez la fonction analytique suivante
def parse(self, request, response):
job_list = response.xpath("//li[contains(@class, 'con_list_item')]")
for job in job_list:
job_name = job.xpath("./@data-positionname").extract_first()
company = job.xpath("./@data-company").extract_first()
salary = job.xpath("./@data-salary").extract_first()
job_url = job.xpath(".//a[@class='position_link']/@href").extract_first()
print(job_name, company, salary, job_url)
Nous avons analysé le nom du poste, la société, le salaire et l'adresse détaillée du poste. La logique normale devrait envoyer l'adresse détaillée en tant que tâche pour obtenir les détails.
def parse(self, request, response):
job_list = response.xpath("//li[contains(@class, 'con_list_item')]")
for job in job_list:
job_name = job.xpath("./@data-positionname").extract_first()
company = job.xpath("./@data-company").extract_first()
salary = job.xpath("./@data-salary").extract_first()
job_url = job.xpath(".//a[@class='position_link']/@href").extract_first()
print(job_name, company, salary, job_url)
yield feapder.Request(
job_url, callback=self.parse_detail, cookies=response.cookies.get_dict()
) # 携带列表页返回的cookie,回调函数指向详情解析函数
def parse_detail(self, request, response):
print(response.text)
# TODO 解析详情
Mais la condition est que les détails soient mis à jour tous les 7 jours, et la liste n'indique pas qu'elle doit être mise à jour. Par conséquent, afin d'optimiser, écrivez un robot distinct pour les détails. Ce robot est uniquement responsable des tâches de les données et les détails de production de la liste.
Beaucoup de gens apprennent le python et ne savent pas par où commencer.
Beaucoup de gens apprennent python et après avoir maîtrisé la grammaire de base, ils ne savent pas où trouver des cas pour commencer.
De nombreuses personnes qui ont fait des études de cas ne savent pas comment acquérir des connaissances plus avancées.
Donc pour ces trois types de personnes, je vais vous fournir une bonne plateforme d'apprentissage, gratuite pour recevoir des tutoriels vidéo, des e-books et le code source du cours!
Groupe QQ: 705933274
3.3 Stockage des données
Créer une table
Fiche technique de la liste des emplois lagou_job_list
CREATE TABLE `lagou_job_list` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
`job_name` varchar(255) DEFAULT NULL COMMENT '职位名称',
`company` varchar(255) DEFAULT NULL COMMENT '公司',
`salary` varchar(255) DEFAULT NULL COMMENT '薪资',
`job_url` varchar(255) DEFAULT NULL COMMENT '职位地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
Tableau des tâches détaillé lagu_job_detail_task
CREATE TABLE `lagou_job_detail_task` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`url` varchar(255) DEFAULT NULL,
`state` int(11) DEFAULT '0' COMMENT '任务状态(0未做,1完成,2正在做,-1失败)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
Méthode de stockage des données
Il existe de nombreuses façons de stocker des données dans la base de données, en important directement pymysql, puis en épissant des instructions sql dans la base de données, ou en utilisant MysqlDB fourni avec le framework. Cependant, Feapder a un moyen plus pratique d'entreposage, l'entreposage automatique
Le stockage automatique d' AirSpider n'est pas pris en charge, car il est relativement léger. Afin de conserver la fonctionnalité légère, l'auteur ne prend pas en charge le stockage automatique pour le moment. Mais le robot d'exploration distribué Spider est pris en charge, nous intégrerons directement la classe à la place que Spider peut
class ListSpider(feapder.AirSpider):
À
class ListSpider(feapder.Spider):
Générer un élément
L'élément correspond à la table un par un, et est lié au mécanisme de stockage de données, et peut être généré par la commande feapder.
Commencez par configurer les informations de connexion à la base de données, qui sont configurées dans le paramètre
Générer un élément:
> cd items
> feapder create -i lagou_job_list
> feapder create -i lagou_job_detail_task
Stockage de données
def parse(self, request, response):
job_list = response.xpath("//li[contains(@class, 'con_list_item')]")
for job in job_list:
job_name = job.xpath("./@data-positionname").extract_first()
company = job.xpath("./@data-company").extract_first()
salary = job.xpath("./@data-salary").extract_first()
job_url = job.xpath(".//a[@class='position_link']/@href").extract_first()
# 列表数据
list_item = lagou_job_list_item.LagouJobListItem()
list_item.job_name = job_name
list_item.company = company
list_item.salary = salary
list_item.job_url = job_url
yield list_item # 直接返回,框架实现批量入库
# 详情任务
detail_task_item = lagou_job_detail_task_item.LagouJobDetailTaskItem()
detail_task_item.url = job_url
yield detail_task_item # 直接返回,框架实现批量入库
Les données sont renvoyées au framework sous forme d'élément de rendement, et le framework est automatiquement stocké par lots
3.4 Code général
import feapder
from items import *
class ListSpider(feapder.Spider):
def start_requests(self):
yield feapder.Request(
"https://www.lagou.com/jobs/list_%E7%88%AC%E8%99%AB?labelWords=&fromSearch=true&suginput=",
render=True,
)
def parse(self, request, response):
job_list = response.xpath("//li[contains(@class, 'con_list_item')]")
for job in job_list:
job_name = job.xpath("./@data-positionname").extract_first()
company = job.xpath("./@data-company").extract_first()
salary = job.xpath("./@data-salary").extract_first()
job_url = job.xpath(".//a[@class='position_link']/@href").extract_first()
# 列表数据
list_item = lagou_job_list_item.LagouJobListItem()
list_item.job_name = job_name
list_item.company = company
list_item.salary = salary
list_item.job_url = job_url
yield list_item # 直接返回,框架实现批量入库
# 详情任务
detail_task_item = lagou_job_detail_task_item.LagouJobDetailTaskItem()
detail_task_item.url = job_url
yield detail_task_item # 直接返回,框架实现批量入库
if __name__ == "__main__":
spider = ListSpider(redis_key="feapder:lagou_list")
spider.start()
redis_key est l'emplacement où la file d'attente des tâches est stockée dans redis.
Exécutez directement et observez que les données ont été automatiquement stockées dans la base de données
4. Écrire les détails du robot d'exploration
Contrairement aux robots d'exploration de pages de liste, les données détaillées doivent être mises à jour tous les 7 jours.
Afin d'afficher les données de séries chronologiques, nous collectons des données tous les 7 jours. Les données doivent contenir des informations sur les lots et diviser les données selon la dimension 7 jours.
Avant de contacter le framework feapder, nous devons envisager de transférer les tâches de la table des tâches détaillée au robot d'exploration par lots, et également de maintenir l'état des tâches et les informations de lot mentionnées ci-dessus. Et afin de garantir l'actualité des données, il est nécessaire de surveiller la progression de la collecte, et l'écriture d'un robot d'exploration est très fastidieuse.
Alors, comment fait Feapder? Afin de gagner de la place, donnez directement le code complet:
import feapder
from items import *
class DetailSpider(feapder.BatchSpider):
def start_requests(self, task):
task_id, url = task
yield feapder.Request(url, task_id=task_id, render=True)
def parse(self, request, response):
job_name = response.xpath('//div[@class="job-name"]/@title').extract_first().strip()
detail = response.xpath('string(//div[@class="job-detail"])').extract_first().strip()
item = lagou_job_detail_item.LagouJobDetailItem()
item.title = job_name
item.detail = detail
item.batch_date = self.batch_date # 获取批次信息,批次信息框架自己维护
yield item # 自动批量入库
yield self.update_task_batch(request.task_id, 1) # 更新任务状态
if __name__ == "__main__":
spider = DetailSpider(
redis_key="feapder:lagou_detail", # redis中存放任务等信息的根key
task_table="lagou_job_detail_task", # mysql中的任务表
task_keys=["id", "url"], # 需要获取任务表里的字段名,可添加多个
task_state="state", # mysql中任务状态字段
batch_record_table="lagou_detail_batch_record", # mysql中的批次记录表
batch_name="详情爬虫(周全)", # 批次名字
batch_interval=7, # 批次周期 天为单位 若为小时 可写 1 / 24
)
# 下面两个启动函数 相当于 master、worker。需要分开运行
# spider.start_monitor_task() # 下发及监控任务
spider.start() # 采集
Nous exécutons respectivement spider.start_monitor_task () et spider.start (), et une fois le robot terminé, observez la base de données
Tableau des tâches : lagu_job_detail_task
Toutes les tâches ont été achevées et le cadre dispose d'un mécanisme pour renvoyer les tâches après des tâches manquantes jusqu'à ce que toutes les tâches soient terminées
Fiche technique : lagu_job_detail:
Les données contiennent des informations de temps de lot, et nous pouvons diviser les données en fonction de cette heure. Le lot actuel est le 19 mars. Si le lot se produit dans les 7 jours, le prochain lot aura lieu le 26 mars.
Démarrez le robot d'exploration à plusieurs reprises pendant ce lot. S'il n'y a pas de nouvelle tâche, le robot ne récupérera pas
spider.start_monitor_task ()
spider.start ()
Table de lots : lagu_detail_batch_record
La table de lots est spécifiée dans les paramètres de démarrage et est générée automatiquement. La table de lots enregistre en détail l'état de capture de chaque lot, comme le nombre total de tâches, le montant effectué, le montant de l'échec, s'il a été terminé et d'autres informations.
5. Intégration
À l'heure actuelle, le robot d'exploration de liste et le robot d'exploration détaillé ont été écrits. L'entrée en cours d'exécution est distribuée dans deux fichiers, ce qui est compliqué à gérer. Feapder recommande de l'écrire dans main.py.
from feapder import ArgumentParser
from spiders import *
def crawl_list():
"""
列表爬虫
"""
spider = list_spider.ListSpider(redis_key="feapder:lagou_list")
spider.start()
def crawl_detail(args):
"""
详情爬虫
@param args: 1 / 2 / init
"""
spider = detail_spider.DetailSpider(
redis_key="feapder:lagou_detail", # redis中存放任务等信息的根key
task_table="lagou_job_detail_task", # mysql中的任务表
task_keys=["id", "url"], # 需要获取任务表里的字段名,可添加多个
task_state="state", # mysql中任务状态字段
batch_record_table="lagou_detail_batch_record", # mysql中的批次记录表
batch_name="详情爬虫(周全)", # 批次名字
batch_interval=7, # 批次周期 天为单位 若为小时 可写 1 / 24
)
if args == 1:
spider.start_monitor_task()
elif args == 2:
spider.start()
if __name__ == "__main__":
parser = ArgumentParser(description="xxx爬虫")
parser.add_argument(
"--crawl_list", action="store_true", help="列表爬虫", function=crawl_list
)
parser.add_argument(
"--crawl_detail", type=int, nargs=1, help="详情爬虫(1|2)", function=crawl_detail
)
parser.start()
Affichez la commande de démarrage:
> python3 main.py --help
usage: main.py [-h] [--crawl_list] [--crawl_detail CRAWL_DETAIL]
xxx爬虫
optional arguments:
-h, --help show this help message and exit
--crawl_list 列表爬虫
--crawl_detail CRAWL_DETAIL
详情爬虫(1|2)
Démarrez le robot d'exploration de liste:
python3 main.py --crawl_list
Démarrez le maître du robot d'exploration détaillé
python3 main.py --crawl_detail 1
Démarrez le robot d'exploration détaillé
python3 main.py --crawl_detail 2
Pour résumer
Cet article prend un site Web de recrutement comme exemple et présente l'ensemble du processus de collecte de données à l'aide de feapder. Ce qui implique l'utilisation de trois robots AirSpider, Spider, BatchSpider.
- Le robot d'exploration AirSpider est relativement léger et a de faibles coûts d'apprentissage. Face à un petit volume de données, pas besoin de continuer l'exploration sans points d'arrêt et pas besoin de collecte distribuée, ce robot peut être utilisé.
- Spider est un robot d'exploration distribué basé sur redis, adapté à la collecte massive de données et prend en charge des fonctions telles que l'exploration continue aux points d'arrêt, les alarmes du robot d'exploration et le stockage automatique des données.
- BatchSpider est un robot d'exploration de lots distribué. Pour les données qui doivent être collectées périodiquement, ce robot a la priorité.
En plus de prendre en charge le rendu et le téléchargement du navigateur, feapder prend également en charge le pipeline, qui peut être personnalisé par les utilisateurs pour faciliter l'ancrage avec d'autres bases de données.
Des alarmes riches sont intégrées dans le cadre et nous serons avertis à temps en cas de problème avec le robot d'exploration pour garantir la rapidité des données.
- Calculer la vitesse d'exploration du robot d'exploration en temps réel, estimer le temps restant et prédire s'il expirera dans le cycle d'exploration spécifié
- Reptile coincé alarme
- Trop d'alarmes de tâches du robot d'exploration ont échoué, ce qui peut être causé par des modifications ou un blocage du modèle de site Web
- Télécharger la surveillance de l'état