基于scrapy的分布式爬虫(5):伯乐在线文章爬取

当我们完成了环境配置之后,所要做的就是使用 scrapy 爬取相关数据了。

接下来,我们以伯乐在线网站为例,进行实际操作。

目的:抓取 http://blog.jobbole.com/all-posts/ 网址下的全部文章信息,包括“标题”、“创建时间”、“封面图”、“点赞数”、“收藏数”、“评论数”以及“文章内容”。


新建项目

首先,我们要完成scrapy项目的新建,在cmd下运行如下指令:

workon article(此为虚拟环境名称)
scrapy startproject articlespider(此为 scrapy 项目名称)

如图所示:
新建项目1

然后,根据提示,再运行指令:

cd test1
scrapy genspider bole(文件名称) http://blog.jobbole.com/all-posts/(网址)

新建项目2

接下来,我们用 pycharm 打开这个项目,并配置解释器即可,具体方法如下:

  1. 打开 pycharm,open project,然后在主目录下新建一个 main.py
    新建文件
  2. 在 File - Setting 中,输入project,选择 project interpreter。然后点击 add local,找到虚拟环境目录下 article - Scripts - python.exe,设置为解释器。
    这里写图片描述

模块分析

仔细观察我们新建的 scrapy 项目,发现其包含几个.py 文件,这些文件直接的关系为:
这里写图片描述

main 文件

用于执行爬虫程序,也可以进行相关debug。

from scrapy.cmdline import execute

import sys
import os

sys.path.append(os.path.dirname(os.path.abspath(__file__)))
# 将文件路径进行添加

execute(["scrapy", "crawl", "jobbole"])

jobbole 文件

爬虫函数主程序,具体解释见代码:

# -*- coding: utf-8 -*-
import scrapy
import re
import datetime

from ArticleSpider.items import JobBoleArticleItem
from scrapy.http import Request
from urllib import parse
from scrapy.loader import ItemLoader
from ArticleSpider.items import ArticleItemLoader

class JobboleSpider(scrapy.Spider):
    name = 'jobbole'
    start_urls = ['http://python.jobbole.com/all-posts/']

    def parse(self, response):
        ## 提取全部文章url并交给scrapy进行下载后解析
        ## 具体提取方法可以采用 xpath 和 css
        ## 使用谷歌浏览器可以直接 copy xpath
        ## 火狐浏览器的 xpath 为动态加载后的,无法提取到相关元素,不推荐。
        post_nodes = response.xpath("//div[@id='archive']/div[@class='post floated-thumb']/div[@class='post-thumb']/a")
        for post_node in post_nodes:
            image_url = post_node.css("img::attr(src)").extract_first("")
            # 封面图网址
            post_url = post_node.css("::attr(href)").extract_first()
            # 文章网址,用于传递为参数,进入文章页面查找相关信息
            yield Request(url = parse.urljoin(response.url, post_url), meta = {"front_image_url":image_url}, callback = self.parse_detail)

        ## 提取下一页url并交给scrapy进行下载
        next_url = response.xpath("//div[@class='navigation margin-20']/a[@class='next page-numbers']/@href").extract_first()
        # 提取“下一页”网址,用于遍历全部网页
        if next_url:
            yield Request(url = parse.urljoin(response.url, next_url), callback = self.parse)

    def parse_detail(self, response):

        # 通过item loader加载item
        item_loader = ArticleItemLoader(item=JobBoleArticleItem(), response=response)
        item_loader.add_css("title", ".entry-header h1::text")
        item_loader.add_css("create_date", "p.entry-meta-hide-on-mobile::text")
        item_loader.add_value("url", response.url)
        front_image_url = response.meta.get("front_image_url", "")
        item_loader.add_value("front_image_url", [front_image_url])
        item_loader.add_css("like_nums", ".vote-post-up h10::text")
        item_loader.add_css("collect_nums", ".bookmark-btn::text")
        item_loader.add_css("comment_nums", "a[href='#article-comment'] span::text")
        item_loader.add_css("content", "div.entry")

        article_items = item_loader.load_item()

        yield article_items

items 文件

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html

import datetime
import scrapy
import re
from scrapy.loader.processors import MapCompose, TakeFirst
from scrapy.loader import ItemLoader


def date_convert(value):
# 时间转换函数,将create_time转换为正确格式,如无正确时间,则使用当前时间。
    try:
        create_date = datetime.datetime.strptime(value, "%Y/%m/%d").date()
    except Exception as e:
        create_date = datetime.datetime.now().date()
    return create_date


def get_nums(value):
# 提取“评论”和“收藏”数字
    match_re = re.search(r"\d+", value)
    if match_re:
        nums = int(match_re.group(0))
    else:
        nums = 0
    return nums


def return_value(value):
    return value


class ArticleItemLoader(ItemLoader):
    default_output_processor = TakeFirst()


class JobBoleArticleItem(scrapy.Item):
    title = scrapy.Field()
    create_date = scrapy.Field(
        input_processor = MapCompose(date_convert)
    )
    url = scrapy.Field()
    front_image_url = scrapy.Field(
        output_processor = MapCompose(return_value)
    )
    like_nums = scrapy.Field()
    collect_nums = scrapy.Field(
        input_processor=MapCompose(get_nums)
    )
    comment_nums = scrapy.Field(
        input_processor=MapCompose(get_nums)
    )
    content = scrapy.Field()

pipelines 文件

import codecs
import json

class JsonWithEncodingPipeline(object):
    # 自定义存储json文件
    def __init__(self):
        self.file = open("article.json", "w", encoding='utf-8')

    def process_item(self, item, spider):
        lines = json.dumps(dict(item), ensure_ascii=False) + '\n'
        self.file.write(lines)
        return item

setting 文件

setting 中需要注意几点:

  1. ROBOTSTXT_OBEY = False :这是将网站正常访问检查关闭,以便爬虫能够运行。
  2. 在 items_pipelines 处需要进行如下设置,其中后面的数字表示执行顺序,数字越小,执行顺序越靠前
ITEM_PIPELINES = {
   'ArticleSpider.pipelines.JsonExporterPipeline': 2,
   # 用于保存json文件
   'scrapy.pipelines.images.ImagesPipeline': 1,
   # 用于下载图片
}
IMAGES_URLS_FIELD = "front_image_url"
project_dir = os.path.abspath(os.path.dirname(__file__))
IMAGES_STORE = os.path.join(project_dir, 'images')
# 设置下载图片存放路径
发布了21 篇原创文章 · 获赞 24 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/fIsh1220Fish/article/details/79862070
今日推荐