抓取知乎学习Scrapy

每一篇讲解scrapy框架的文章,都会以这张图来说明,对于一个小白,第一次看到这张图的时候,肯定是懵逼的!先不管这张图,下面我以抓取知乎的实例,说明这个框架!

通过以下命令,我们会建立一个scrapy框架的抓取知乎网页的工程:

scrapy startproject zhihu

这个时候就会生成以下这些文件!

这个时候我们需要进入这个工程zhihu,输入以下命令,建立spider文件!

scrapy genspider zhihuspider zhihu.com

这个时候就会生成以下这些文件!

这个时候,我们整个爬虫的框架就建立了!我们这个时候发现,这些文件的名字和上面框架图这个组件的名字好像蛮像的哦!!!

既然框架实现了,那我们就开始爬呗!本文要实现的是以轮子哥的主页为起点,爬取他关注的人和关注他的人的基本信息!

我们的zhihuspider.py这个文件实现的类型就是对应框架图的Spiders,它会向调度器Scheduler发起Requests请求,调度器会向Downloader发起请求,然后把返回Response返回给Spiders,中间还会通过Spider Middleware和Downloader Middleware这两玩意儿,我们先不管它们,先实现zhihuspider.py再说!

from scrapy import Request,Spider
import json
from zhihu.items import UserItem

class ZhihuspiderSpider(Spider):
    name = 'zhihuspider'
    allowed_domains = ['www.zhihu.com']
    start_urls = ['https://www.zhihu.com/']

    follow_url = 'https://www.zhihu.com/api/v4/members/{user}/followees?include={include}&offset={offset}&limit={limit}'
    followers_url = 'https://www.zhihu.com/api/v4/members/{user}/followers?include={include}&offset={offset}&limit={limit}'
    start_user = 'excited-vczh'
    follows_query = 'data[*].answer_count,articles_count,gender,follower_count,is_followed,is_following,badge[?(type=best_answerer)].topics'
    followers_query = 'data[*].answer_count,articles_count,gender,follower_count,is_followed,is_following,badge[?(type=best_answerer)].topics'

    user_url = 'https://www.zhihu.com/api/v4/members/{user}?include={include}'
    user_query = ' allow_message,is_followed,is_following,is_org,is_blocking,employments,answer_count,follower_count,articles_count,gender,badge[?(type=best_answerer)].topics'

    def start_requests(self):
        yield Request(self.user_url.format(user=self.start_user,include=self.user_query),callback=self.parse_user)

        yield Request(self.follow_url.format(user=self.start_user,include=self.follows_query,offset=0,limit=20),
                      callback=self.parse_follows)
        yield Request(self.followers_url.format(user=self.start_user, include=self.followers_query, offset=0, limit=20),
                      callback=self.parse_followers)

    def parse_user(self,response):
        result = json.loads(response.text)
        item = UserItem()
        for field in item.fields:
            if field in result.keys():
                item[field] = result.get(field)

        yield item

        yield Request(self.follow_url.format(user=result.get('url_token'),include=self.follows_query,limit=20,offset=0),
                      self.parse_follows)
        yield Request(self.followers_url.format(user=result.get('url_token'), include=self.followers_query, limit=20, offset=0),
                      self.parse_followers)

    def parse_follows(self, response):
        results = json.loads(response.text)

        if 'data' in results.keys():
            for result in results.get('data'):
                yield Request(self.user_url.format(user=result.get('url_token'),include=self.user_query),self.parse_user)

        if 'paging' in results.keys() and results.get('paging').get('is_end') == False:
            next_page = results.get('paging').get('next')
            yield Request(next_page,self.parse_follows)

我们通过这个程序,可以看到它主要做两件事情,1、定义爬取网站的动作;2、分析爬取下来的网页。

以初始的url来初始化Request,并设置回调函数。当Request成功请求并返回时,Response生成并作为参数传回回调函数!我们看到的callback就是回调函数,当指定了该回调函数的请求完成后,获取到响应,引擎会将该响应作为参数传递给这个回调函数。回调函数进行解析或生成下一个请求,回调函数如上文的parse函数所示。

在代码中,有这样一句item = UserItem(),这个是用来实例化Item的,我们可以把它理解成一个字典,在声明的时候需要实例化,而它的实现是在items.py中。

from scrapy import Item,Field

class UserItem(Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    name = Field()
    answer_count = Field()
    follower_count = Field()
    headline = Field()
    url = Field()
    url_token = Field()

Item是保存爬取数据的容器,它的使用方法和字典类似!相比于字典,Item多了额外的保护机制,可以避免拼写错误或者定义字段错误!

在框架图中,Spider的数据items会到Item Pipelines中!上面我们说明了Item了,下面就说说Item Pipelines!注意,此处Item Pipelines中Item和上面那个item.py的item不是指的同一个东西啊!!!

Item Pipelines主要做以下这些事情,1、清理HTML数据;2、验证爬取数据,检查爬取字段;3、查重并丢弃重复内容;4、将爬取结果保存到数据库。

我们先看看pipelines.py的实现!

import pymongo

class MongoPipeline(object):

    collection_name = 'user'

    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_uri=crawler.settings.get('MONGO_URI'),
            mongo_db=crawler.settings.get('MONGO_DB','items')
        )

    def open_spider(self,spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]

    def close_spider(self, spider):
        self.client.close()

    def process_item(self, item, spider):
        #self.db[self.collection_name].insert_one(dict(item))
        self.db[self.collection_name].update({'url_token':item['url_token']},{'$set':dict(item)},True)
        return item

这个程序实现的方法中,process_item()是必须实现的方法,被定义的Item Pipeline会默认调用这个方法对Item进行处理。比如这里就是将数据写入数据库!这里我们看到有两个参数,其中item就是每次spider生成的Item都会作为参数传递过来,而spider就是spider的实例!

from_crawler()方法是一个类方法,用@classmethod标识,是一种依赖注入的方式。它的参数是crawler,通过crawler对象,我们会拿到Scrapy的所有核心组件,如全局配置的每个信息,然后创建一个pipeline的实例!参数cls就是class,最后返回一个class实例!

这样,我们就把框架图的组件都有了说明,还剩下Spider Middleware和Downloader Middleware。这两个东西的实现在middleware.py这个文件中!

其实这两个都是中间的处理模块,其中Downloader Middleware即下载中间件,处于Request和Response之间的处理模块!可以用来修改User-Agent、处理重定向、设置代理、失败重试、设置Cookie等功能!

而Spider Middleware主要用来处理Request、Response、Item,是介于Scrapy和Spider处理机制的钩子框架!

现在把框架上面的东西都讲完了,还有一个setting.py这个文件,顾名思义,就是做一些配置而已,比如我们用到的MongoDB就是在里面配置的!

ITEM_PIPELINES = {
    'zhihu.pipelines.MongoPipeline': 300,
}

MONGO_URI = 'localhost:27017'
MONGO_DB = 'zhihu'

那么,整个框架的代码就讲完了,运行它,抓取到下面这样的数据了!

参考《Python3网络爬虫实战》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的scrapy爬取知乎热门话题的案例: 首先,需要安装scrapy和其他需要的库: ``` pip install scrapy pip install requests pip install scrapy-splash ``` 然后,创建一个新的scrapy项目: ``` scrapy startproject zhihu cd zhihu ``` 接着,在`settings.py`中添加一些配置: ```python BOT_NAME = 'zhihu' SPIDER_MODULES = ['zhihu.spiders'] NEWSPIDER_MODULE = 'zhihu.spiders' ROBOTSTXT_OBEY = False DOWNLOAD_DELAY = 3 DOWNLOADER_MIDDLEWARES = { 'scrapy_splash.SplashCookiesMiddleware': 723, 'scrapy_splash.SplashMiddleware': 725, 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810, } SPLASH_URL = 'http://localhost:8050' DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter' HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage' ``` 在这里,我们使用了Splash来渲染网页,因此需要添加一些相关的配置。`DOWNLOAD_DELAY`是下载延迟时间,为了避免被网站封禁,最好设置一个较长的时间。 接下来,创建一个名为`zhihu_spider.py`的Spider类: ```python import scrapy from scrapy_splash import SplashRequest class ZhihuSpider(scrapy.Spider): name = 'zhihu' allowed_domains = ['www.zhihu.com'] start_urls = ['https://www.zhihu.com/hot'] script = ''' function main(splash, args) assert(splash:go(args.url)) assert(splash:wait(2)) return splash:html() end ''' def start_requests(self): for url in self.start_urls: yield SplashRequest(url, self.parse, endpoint='execute', args={ 'lua_source': self.script }) def parse(self, response): for item in response.css('.HotItem'): yield { 'title': item.css('.HotItem-title a::text').get(), 'link': item.css('.HotItem-title a::attr(href)').get(), } ``` 在这里,我们使用了SplashRequest来请求页面,并使用Lua脚本来等待页面加载完毕。然后,我们使用CSS选择器来提取热门话题的标题和链接,并将它们存储在字典中,然后使用yield返回。 最后,运行爬虫: ``` scrapy crawl zhihu -o zhihu.csv ``` 这将抓取知乎热门话题的标题和链接,并将它们存储在CSV文件中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值