scrapy 框架 爬取 网站 实例

scrapy框架爬取网站
比如https://www.dushu.com/news/99.html 爬取这个分类下每篇文章的标题 作者 内容等

首先 创建工程
终端输入

scrapy startproject News

进入工程目录
cd News
创建 spider 文件 主要获取网页 及 处理在逻辑写在其中

 scrapy genspider history www.dushu.com

这个读书网站是比较规则的 有 信息页 及详情页 可使用 CrawlSpider 爬取
先使用常规方法爬取
在history.py 中实现 页面获取解析逻辑
页面中自带一个类 继承 scrapy.Spider
类中有三个属性

name spider名。在执行爬虫文件时会用到
allowed_domains 允许的域名 www.dushu.com 可以删除
start_urls 默认识别解析的网页 换为https://www.dushu.com/news/99.html

scapy执行时 会调用 start_request()方法。。。默认是没有的。。。不是一定要重写该方法该方法会将根据网址生成 request请求。scrapy.Request(url)默认callback回调方法是parse 如果我们重写该方法要和默认执行一样 则为

def start_requests(self):
    for url in self.start_urls:
        yield scrapy.Request(url)

根据start_url中内容生成迭代器

parse函数负责解析 response网页

def parse(self,response)
	# 获取下一页的链接
    next_page_selector = response.xpath('//a[contains(text(),"下一页")]/@href')
    if next_page_selector:
        next_page_url = response.urljoin(next_page_selector.extract_first())
        print(next_page_url)
        # 生成请求 没有callback 默认为parse
        yield scrapy.Request(next_page_url)

根据response我们可以获取下一页 。我们可以直接将下一页的链接使用scrapy.Request()包裹后 yield 这样根据新的url生成的request回调函数仍是parse。会继续执行直到下一页链接为空
这样我们就获得了横向的数据。即页面。而详情页的链接都包括在信息页中
接下来 获取详情页的信息。使用新的函数处理获取到的页面信息

news_url_seletors = response.xpath('//div[contains(@class,"news-item")]/p/a/@href').extract()
for news_url_end in news_url_seletors:
    news_url = response.urljoin(news_url_end)
    print(news_url)
    yield scrapy.Request(news_url,callback=self.content_parse)

这仍然是parse函数的一部分
callback=self.content_parse content_parse是我们自己定义的处理详情页的函数

def content_parse(self,response):
    title = response.xpath('//h1/text()').extract_first()
    author = response.xpath('//div[@class="article-info"]/span/text()')[0].extract()
    send_time = response.xpath('//div[@class="article-info"]/span/text()')[1].extract()
    address = response.xpath('//div[@class="article-info"]/span/text()')[2].extract()
    content = '\n'.join(response.xpath('//div[@class="text"]/p/text()').extract())

    news_item = NewsItem()
    news_item['title'] = title
    news_item['author'] = author
    news_item['send_time'] = send_time
    news_item['address'] = address
    news_item['content'] = content

    yield news_item

可以看出我们yield了一个item
item是scrapy中的数据处理类型 在items.py中定义定义内容根据我们想要获取的信息设计。使用时导入Newsitem

class NewsItem(scrapy.Item):
    title = scrapy.Field()
    author = scrapy.Field()
    send_time = scrapy.Field()
    address = scrapy.Field()
    content = scrapy.Field()

如果yield Request会根据回调函数处理获取到的response.而item则会经由中间键得到处理
处理item的逻辑在pipelines.py

class NewsPipeline(object):
    def open_spider(self,spider):
        print('开始处理数据')
        # 建立连接
        self.client = pymongo.MongoClient(host='10.31.153.34',port=27017)
        # 建立或连接库
        self.db = self.client['news']
        # 建立表
        self.collection = self.db['culture']

    def process_item(self, item, spider):
        self.collection.insert(dict(item))
        self.collection.save()
        return item

    def close_spider(self,spider):
        self.client.close()
        print('处理完毕')

open_spider()和close_spider()会在爬虫开始执行与结束执行时调用。而process_item()每当有新的item时都会执行 此处简单起见保存到mongodb中。

为了能使pipelines.py中类能够执行。需要在setting中打开设置

ITEM_PIPELINES = {
   # 'ReadNews.pipelines.ReadnewsPipeline': 300,
    'ReadNews.pipelines.NewsPipeline': 300,
}

接下来只要终端执行。就可以看到效果

scrapy crawl history

这是常规使用方法。对于比较规则的数据。我们可以使用更方便的方法

# -*- coding: utf-8 -*-
import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractor import LinkExtractor

from ..items import NewsItem

class NewsSpider(CrawlSpider):
    name = 'news'
    # allowed_domains = ['www.dushu.com']
    start_urls = ['https://www.dushu.com/news/86.html']

    rules = (
        # 横向 查找 页  递归查找 没有指定 callback则默认 parse
        # parse 不做解析因此不用写。只是获取页面 rules根据页面中有无符合Rule 继续查找
        Rule(LinkExtractor(restrict_xpaths='//a[contains(text(),"下一页")]'),follow=True),
        # 纵向  查找 详情页  详情页 不再继续作为  response 按照规则继续查找
        Rule(LinkExtractor(restrict_xpaths='//div[contains(@class,"news-item")]/p/a'),callback='content_parse',follow=False),
    )


    def content_parse(self,response):
        title = response.xpath('//h1/text()').extract_first()
        author = response.xpath('//div[@class="article-info"]/span/text()')[0].extract()
        send_time = response.xpath('//div[@class="article-info"]/span/text()')[1].extract()
        address = response.xpath('//div[@class="article-info"]/span/text()')[2].extract()
        content = '\n'.join(response.xpath('//div[@class="text"]/p/text()').extract())

        news_item = NewsItem()
        news_item['title'] = title
        news_item['author'] = author
        news_item['send_time'] = send_time
        news_item['address'] = address
        news_item['content'] = content

        yield news_item

继承的类是CrawlSpider。在rules中定义的查找规则。
根据follow=True 则会根据获取到的response内容继续根据rules规则继续查找.False则不会进行对获取到的response继续查找
LinkExtractor可以获取标签所带链接

scrapy crawl news 

可以获取同样的效果

你可能感兴趣的:(爬虫,Scrapy)