web-dev-qa-db-fra.com

Scrapy - Extrait des articles de la table

J'essaie de comprendre Scrapy, mais je vis quelques impasses.

J'ai 2 tableaux sur une page et j'aimerais extraire les données de chacun puis passer à la page suivante.

Les tableaux ressemblent à ceci (le premier s'appelle Y1, le second est Y2) et les structures sont les mêmes.

<div id="Y1" style="margin-bottom: 0px; margin-top: 15px;">
                                <h2>First information</h2><hr style="margin-top: 5px; margin-bottom: 10px;">                    

                <table class="table table-striped table-hover table-curved">
                    <thead>
                        <tr>
                            <th class="tCol1" style="padding: 10px;">First Col Head</th>
                            <th class="tCol2" style="padding: 10px;">Second Col Head</th>
                            <th class="tCol3" style="padding: 10px;">Third Col Head</th>
                        </tr>
                    </thead>
                    <tbody>

                        <tr>
                            <td>Info 1</td>
                            <td>Monday 5 September, 2016</td>
                            <td>Friday 21 October, 2016</td>
                        </tr>
                        <tr class="vevent">
                            <td class="summary"><b>Info 2</b></td>
                            <td class="dtstart" timestamp="1477094400"><b></b></td>
                            <td class="dtend" timestamp="1477785600">
                            <b>Sunday 30 October, 2016</b></td>
                        </tr>
                        <tr>
                            <td>Info 3</td>
                            <td>Monday 31 October, 2016</td>
                            <td>Tuesday 20 December, 2016</td>
                        </tr>


                    <tr class="vevent">
                        <td class="summary"><b>Info 4</b></td>                      
                        <td class="dtstart" timestamp="1482278400"><b>Wednesday 21 December, 2016</b></td>
                        <td class="dtend" timestamp="1483315200">
                        <b>Monday 2 January, 2017</b></td>
                    </tr>



                </tbody>
            </table>

Comme vous pouvez le constater, la structure est un peu incohérente, mais tant que je peux obtenir chaque td et chaque sortie au format csv, je serai heureux.

J'ai essayé d'utiliser xPath mais cela ne m'a que plus perturbé.

Ma dernière tentative:

import scrapy

class myScraperSpider(scrapy.Spider):
name = "myScraper"

allowed_domains = ["mysite.co.uk"]
start_urls =    (
                'https://mysite.co.uk/page1/',
                )

def parse_products(self, response):
    products = response.xpath('//*[@id="Y1"]/table')
    # ignore the table header row
    for product in products[1:]  
       item = Schooldates1Item()
       item['hol'] = product.xpath('//*[@id="Y1"]/table/tbody/tr[1]/td[1]').extract()[0]
       item['first'] = product.xpath('//*[@id="Y1"]/table/tbody/tr[1]/td[2]').extract()[0]
       item['last'] = product.xpath('//*[@id="Y1"]/table/tbody/tr[1]/td[3]').extract()[0]
       yield item

Aucune erreur ici, mais il renvoie simplement beaucoup d'informations sur l'analyse mais aucun résultat réel.

Mettre à jour:

  import scrapy

       class SchoolSpider(scrapy.Spider):
name = "school"

allowed_domains = ["termdates.co.uk"]
start_urls =    (
                'https://termdates.co.uk/school-holidays-16-19-abingdon/',
                )

  def parse_products(self, response):
  products = sel.xpath('//*[@id="Year1"]/table//tr')
 for p in products[1:]:
  item = dict()
  item['hol'] = p.xpath('td[1]/text()').extract_first()
  item['first'] = p.xpath('td[1]/text()').extract_first()
  item['last'] = p.xpath('td[1]/text()').extract_first()
  yield item

Cela me donne: IndentationError: indent inattendu

si j'exécute le script modifié ci-dessous (grâce à @Granitosaurus) pour générer au format CSV (-o schoolDates.csv) un fichier vide:

import scrapy

class SchoolSpider(scrapy.Spider):
name = "school"
allowed_domains = ["termdates.co.uk"]
start_urls = ('https://termdates.co.uk/school-holidays-16-19-abingdon/',)

def parse_products(self, response):
    products = sel.xpath('//*[@id="Year1"]/table//tr')
    for p in products[1:]:
        item = dict()
        item['hol'] = p.xpath('td[1]/text()').extract_first()
        item['first'] = p.xpath('td[1]/text()').extract_first()
        item['last'] = p.xpath('td[1]/text()').extract_first()
        yield item

Ceci est le journal:

  • 2017-03-23 ​​12:04:08 [scrapy.core.engine] INFO: Araignée ouverte 2017-03-23 ​​12:04:08 [scrapy.extensions.logstats] INFO: Crawled 0 pages (à 0 pages/min), grattées 0 élément (à 0 éléments/min) 2017-03-23 ​​ 12:04:08 [scrapy.extensions.telnet] DEBUG: console Telnet en écoute le ... 2017-03-23 ​​12:04:08 [scrapy.core.engine] DEBUG: Crawled (200) https://termdates.co.uk/robots.txt> ( referer: None) 2017-03-23 ​​ 12:04:08 [scrapy.core.engine] DEBUG: Crawled (200) https://termdates.co.uk/school-holidays-16-19- abingdon /> (référant: aucun) 2017-03-23 ​​12:04:08 [scrapy.core.scraper] ERREUR: erreur d'araignée en cours de traitement de https://termdates.co. uk/school-congés-16-19-abingdon /> (référant: aucun) Traceback (dernier appel en dernier): Fichier "c:\python27\lib\site-packages\twisted\internet\defer.py ", ligne 653, dans _ runCallbacks current.result = callback (current.result, * args, ** kw) Fichier" c:\python27\lib\site-packages\scrapy-1.3.3-py2.7.Egg\scrapy\spiders__init __. py ", ligne 76, dans l'analyse soulève NotImplementedError NotImplementedError 2017-03-23 ​​12:04:08 [scrapy.core.engine] INFO: Closing araignée (fini) 2017 -03-23 ​​ 12:04:08 [scrapy.statscollectors] INFO: Dumping Strap Scrapy stats: {'Downloader/request_bytes': 467, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'téléchargeur/response_bytes': 11311, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason ': ' fini ',' finish_time ': datetime.datetime (2017, 3, 23, 12, 4, 8, 845000),' log_count/DEBUG ': 3,' log_count/ERROR ': 1, ' Log_count/INFO ': 7,' response_received_count ': 2, ' Planificateur/file d'attente ': 1,' planificateur/file d'attente/mémoire ': 1, 'scheduler/enqueued': 1, 'ordonnanceur/enqueued/memory': 1, 'spider_exceptions/NotImplementedError': 1, 'heure_début': datetime.datetime (2017, 3, 23, 12, 4, 8, 356000)} 2017-03-23 ​​12: 0 4:08 [Scrapy.core.engine] INFO: Araignée fermée (fini)

Mise à jour 2 : (Saute la ligne) Ceci place le résultat dans un fichier csv mais saute toutes les lignes.

Le shell affiche {'hol': None, 'last': u '\'\r\n\t\t\t\t\t\t\t\t\t ',' first ': Aucun }

import scrapy

class SchoolSpider(scrapy.Spider):
name = "school"
allowed_domains = ["termdates.co.uk"]
start_urls = ('https://termdates.co.uk/school-holidays-16-19-abingdon/',)

def parse(self, response):
    products = response.xpath('//*[@id="Year1"]/table//tr')
    for p in products[1:]:
        item = dict()
        item['hol'] = p.xpath('td[1]/text()').extract_first()
        item['first'] = p.xpath('td[2]/text()').extract_first()
        item['last'] = p.xpath('td[3]/text()').extract_first()
        yield item

Solution : Merci à @ vold Ceci explore toutes les pages de start_urls et traite la mise en page incohérente

# -*- coding: utf-8 -*-
import scrapy
from SchoolDates_1.items import Schooldates1Item

class SchoolSpider(scrapy.Spider):
name = "school"
allowed_domains = ["termdates.co.uk"]
start_urls = ('https://termdates.co.uk/school-holidays-16-19-abingdon/',
              'https://termdates.co.uk/school-holidays-3-dimensions',)

def parse(self, response):
    products = response.xpath('//*[@id="Year1"]/table//tr')
    # ignore the table header row
    for product in products[1:]:
        item = Schooldates1Item()
        item['hol'] = product.xpath('td[1]//text()').extract_first()
        item['first'] = product.xpath('td[2]//text()').extract_first()
        item['last'] = ''.join(product.xpath('td[3]//text()').extract()).strip()
        item['url'] = response.url
        yield item
7
stutray

Vous devez corriger légèrement votre code. Comme vous avez déjà sélectionné tous les éléments de la table, vous n'avez pas besoin de pointer à nouveau vers une table. Ainsi, vous pouvez raccourcir votre xpath à quelque chose comme ceci td[1]//text().

def parse_products(self, response):
    products = response.xpath('//*[@id="Year1"]/table//tr')
    # ignore the table header row
    for product in products[1:]  
       item = Schooldates1Item()
       item['hol'] = product.xpath('td[1]//text()').extract_first()
       item['first'] = product.xpath('td[2]//text()').extract_first()
       item['last'] = product.xpath('td[3]//text()').extract_first()
       yield item

Edité ma réponse depuis @stutray fournir le lien vers un site.

7
vold

Vous pouvez utiliser des sélecteurs CSS au lieu de xPaths, je trouve toujours que les sélecteurs CSS sont faciles.

def parse_products(self, response):

    for table in response.css("#Y1 table")[1:]:
       item = Schooldates1Item()
       item['hol'] = product.css('td:nth-child(1)::text').extract_first()
       item['first'] = product.css('td:nth-child(2)::text').extract_first()
       item['last'] = product.css('td:nth-child(3)::text').extract_first()
       yield item

De même, n'utilisez pas la balise tbody dans les sélecteurs. La source:

Firefox, en particulier, est connu pour ajouter des éléments à des tableaux. Scrapy, en revanche, ne modifie pas le code HTML de la page d’origine, vous ne pourrez donc extraire aucune donnée si vous utilisez vos expressions XPath.

3
Umair

Je l'ai obtenu avec ces xpath pour la source HTML que vous avez fournie:

products = sel.xpath('//*[@id="Y1"]/table//tr')
for p in products[1:]:
    item = dict()
    item['hol'] = p.xpath('td[1]/text()').extract_first()
    item['first'] = p.xpath('td[1]/text()').extract_first()
    item['last'] = p.xpath('td[1]/text()').extract_first()
    yield item

Ci-dessus suppose que chaque ligne de la table contient 1 élément.

0
Granitosaurus