Scrapy spider 输出 empy csv 文件

Posted

技术标签:

【中文标题】Scrapy spider 输出 empy csv 文件【英文标题】:Scrapy spider outputs empy csv file 【发布时间】:2018-06-12 09:33:30 【问题描述】:

这是我在这里的第一个问题,我正在学习如何自己编码,所以请多多包涵。

我正在做一个最终的 CS50 项目,我正在尝试构建一个网站,该网站可能会汇总来自 edx.org 和其他开放在线课程网站的在线西班牙语课程。我正在使用scrapy框架来废弃edx.org上西班牙语课程的过滤结果......这是我的第一个scrapy蜘蛛,我试图在每个课程链接中获取它的名称(在我得到正确的代码之后,还可以获取描述、课程网址和更多内容)。

from scrapy.item import Field, Item
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractor import LinkExtractor
from scrapy.loader import ItemLoader

class Course_item(Item):
    name = Field()
    #description = Field()
    #img_url = Field()


class Course_spider(CrawlSpider):
    name = 'CourseSpider'
    allowed_domains = ['https://www.edx.org/']
    start_urls = ['https://www.edx.org/course/?language=Spanish']

    rules = (Rule(LinkExtractor(allow=r'/course'), callback='parse_item', follow='True'),)

    def parse_item(self, response):
        item = ItemLoader(Course_item, response)
        item.add_xpath('name', '//*[@id="course-intro-heading"]/text()')

        yield item.load_item()

当我使用“scrapy runspider edxSpider.py -o edx.csv -t csv”运行蜘蛛时,我得到一个空的 csv 文件,我也认为没有进入正确的西班牙语课程结果。

基本上我想进入这个链接edx Spanish courses的每个课程,并获取名称、描述、提供者、页面url和img url。

关于为什么会出现问题的任何想法?

【问题讨论】:

allowed_domains 应该只列出“域”,因此将其更改为仅edx.org 谢谢我修复了那个部分,但它仍然输出一个空的 CSV 必须使用 Scrapy 吗?如果没有,请查看答案:***.com/questions/33109431/course-list-from-edx-api 当我使用 DevTool 检查页面时,我看到很多 class="course-intro-heading" 但没有一个 id="course-intro-heading" 您没有收到任何错误吗?运行您的代码时出现一些错误。 【参考方案1】:

你无法通过简单的请求获取edx 内容,它使用javascript 渲染来动态获取课程元素,因此CrawlSpider 不适用于这种情况,因为你需要在响应中找到特定元素body 来生成一个新的 Request 来得到你需要的东西。

真正的请求(获取课程的网址)是this one,但您需要从之前的响应正文中生成它(尽管您可以访问它并获得正确的数据)。

因此,要生成真正的请求,您需要 script 标签内的数据:

from scrapy import Spider
import re
import json

class Course_spider(Spider):
    name = 'CourseSpider'
    allowed_domains = ['edx.org']
    start_urls = ['https://www.edx.org/course/?language=Spanish']

    def parse(self, response):
        script_text = response.xpath('//script[contains(text(), "Drupal.settings")]').extract_first()
        parseable_json_data = re.search(r'Drupal.settings, (.+)', script_text).group(1)
        json_data = json.loads(parseable_json_data)
        ...

现在您在json_data 上拥有所需的内容,只需要创建字符串 URL。

【讨论】:

非常感谢你!这很有帮助。 @eLRuLL 你能解释一下吗: script_text = parseable_json_data = re.search(r'Drupal.settings, (.+)', t).group(1) 它给了我一个警告未使用变量 t,我不确定这里的 drupal 设置。 google了一下还是不明白 Drupal 与这件事无关,它只是 response.body 中的“文本”,与必要信息的“位置”有关。对不起t,应该是script_text,让我编辑答案。 看看我自己的答案!感谢您的帮助【参考方案2】:

此页面使用 JavaScript 从服务器获取数据并添加到页面。

它使用像

这样的 url
https://www.edx.org/api/catalog/v2/courses/course-v1:IDBx+IDB33x+3T2017

最后一部分是课程编号,可以在 html 中找到

<main id="course-info-page" data-course-id="course-v1:IDBx+IDB33x+3T2017">

代码

from scrapy.http import Request
from scrapy.item import Field, Item
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractor import LinkExtractor
from scrapy.loader import ItemLoader
import json

class Course_spider(CrawlSpider):

    name = 'CourseSpider'
    allowed_domains = ['www.edx.org']
    start_urls = ['https://www.edx.org/course/?language=Spanish']

    rules = (Rule(LinkExtractor(allow=r'/course'), callback='parse_item', follow='True'),)

    def parse_item(self, response):
        print('parse_item url:', response.url)

        course_id = response.xpath('//*[@id="course-info-page"]/@data-course-id').extract_first()

        if course_id:
            url = 'https://www.edx.org/api/catalog/v2/courses/' + course_id
            yield Request(url, callback=self.parse_json)

    def parse_json(self, response):
        print('parse_json url:', response.url)

        item = json.loads(response.body)

        return item

from scrapy.crawler import CrawlerProcess

c = CrawlerProcess(
    'USER_AGENT': 'Mozilla/5.0',
    'FEED_FORMAT': 'csv',     # csv, json, xml
    'FEED_URI': 'output.csv', #     
)
c.crawl(Course_spider)
c.start()

【讨论】:

非常感谢您的回答!!但是你在哪里找到这个初始链接“edx.org/api/catalog/v2/courses/course-v1:IDBx+IDB33x+3T2017” 我使用 Chrome/Firefox 中内置的 DevTool 来查看从浏览器发送到服务器的所有请求(标签 Network)。大多数 JavaScript 使用 AJAX/XHR 请求(标签 Network -> 过滤器 XHR 看看我自己的答案!让它工作了。感谢您的帮助【参考方案3】:
from scrapy.http import Request
from scrapy import Spider
import json


class edx_scraper(Spider):

name = "edxScraper"
start_urls = [
    'https://www.edx.org/api/v1/catalog/search?selected_facets[]=content_type_exact%3Acourserun&selected_facets[]=language_exact%3ASpanish&page=1&page_size=9&partner=edx&hidden=0&content_type[]=courserun&content_type[]=program&featured_course_ids=course-v1%3AHarvardX+CS50B+Business%2Ccourse-v1%3AMicrosoft+DAT206x+1T2018%2Ccourse-v1%3ALinuxFoundationX+LFS171x+3T2017%2Ccourse-v1%3AHarvardX+HDS2825x+1T2018%2Ccourse-v1%3AMITx+6.00.1x+2T2017_2%2Ccourse-v1%3AWageningenX+NUTR101x+1T2018&featured_programs_uuids=452d5bbb-00a4-4cc9-99d7-d7dd43c2bece%2Cbef7201a-6f97-40ad-ad17-d5ea8be1eec8%2C9b729425-b524-4344-baaa-107abdee62c6%2Cfb8c5b14-f8d2-4ae1-a3ec-c7d4d6363e26%2Ca9cbdeb6-5fc0-44ef-97f7-9ed605a149db%2Cf977e7e8-6376-400f-aec6-84dcdb7e9c73'
]

def parse(self, response):
    data = json.loads(response.text)
    for course in data['objects']['results']:
        url = 'https://www.edx.org/api/catalog/v2/courses/' + course['key']
        yield response.follow(url, self.course_parse)

    if 'next' in data['objects'] is not None:
        yield response.follow(data['objects']['next'], self.parse)

def course_parse(self, response):
    course = json.loads(response.text)
    yield
        'name': course['title'],
        'effort': course['effort'],
    

【讨论】:

如果它可以解决您的问题,那么您应该描述您的工作 - 以使其对其他读者有用。

以上是关于Scrapy spider 输出 empy csv 文件的主要内容,如果未能解决你的问题,请参考以下文章

scrapy指定item输出项顺序到csv

Scrapy spider不会在start-url列表上进行迭代

获取Scrapy爬虫输出/结果脚本文件功能

Scrapy Spider没有返回所有元素

Scrapy用pipelines把字典保存为csv格式

Scrapy python csv输出每行之间有空行