一文搞定scrapy爬取众多知名技术博客文章保存到本地数据库,包含:cnblog、csdn、51cto、itpub、jobbole、oschina等...

本文旨在通过爬取一系列博客网站技术文章的实践,介绍一下scrapy这个python语言中强大的整站爬虫框架的使用。各位童鞋可不要用来干坏事哦,这些技术博客平台也是为了让我们大家更方便的交流、学习、提高的,大家千万要珍惜哦(-_-)。

0、开发环境

本文环境:
Win7 64位
Python 版本:3.6.5
pip 版本:18.1
scrapy 版本:1.5
pymysql 版本:0.9.2
Visual Code 版本: 1.28.2
Mysql 5.7 (不会安装的自行百度,这里就不岔话题了)

至于初始化Visual Code(后续文中统一简称:vscode)的Python编程环境,请参考博文建议通过Anaconda3 来搭建python开发环境,省心。

【注】:文中源码有关XPath解析页面内容提取文章元素的解读,本文不再啰嗦重复了,可以参考前面的博文:(2.1.3节有介绍XPath使用)

1、目标介绍

今天的目标网站主要分为两类:

  • 一类是页面通过Ajax异步请求的方式获取翻页文章列表
    比如强大的csdn博客、oschina开源中国就是属于第一类通过Ajax异步加载的方式获取更多内容的
  • 另一类是直接通过界面的上一页、下一页、跳转到第几页的方式直接加载下一页的文章列表
    比如cnblog博客园、51cto、iteye、itpub、jobbole伯乐在线等几个是直接通过页面导航翻页的。
  • > 比如cnblog博客园、51cto、iteye、itpub、jobbole伯乐在线等几个是直接通过页面导航翻页的。

    下面让我们来一个一个分析、实现爬取技术文章保存到本地。

    2、爬取目标

    2.1、csdn博客

    2.1.1 如何判断是否为Ajax方式异步获取的?

    有很多种方式,比如,我们打开火狐浏览器(其它浏览器也一样),按F12打开浏览器的调试模式,选中【网络】,点击【XHR】来过滤异步请求,在这里插入图片描述

    然后输入csdn的网址:,我们看到列表有很多异步的请求,别慌,我们找一下很容易发现其中一个返回json格式的传输数据大小28KB的是我们的目标,点开这个请求发现右边返回的确实是文章列表:在这里插入图片描述

    我们通过关键字articles过滤一下这个请求,再往下滑动发现又发了同样的请求,不过参数不一样:在这里插入图片描述

    分析下这几个网址:1541633731306080``1541579172175664``1541572185652051

    发现其中不一样的就是最后一个shown_offset参数值,这个看起来像时间戳,但是是什么时间戳呢?当前系统时间?上次返回数据的最后一个时间戳?让我们看下响应里面的数据:在这里插入图片描述分析了下可以知道,第二个请求的这个时间戳,正是第一个请求返回数据的最后一个里面的这个值,我们再分析后面几个请求发现都是符合这个规律的,OK了,那接下来就是写爬虫去获取数据了。

    2.1.2 爬虫实现

    打开vscode终端定位到工程目录,例如d:/tmp/csdnnews 输入:scrapy startproject csdnnews 提示成功后,进入到csdnnews目录cd csdnnews 然后输入以下命令创建爬虫:scrapy genspider csdnspider www.csdn.net 其中csdnspider 是爬虫类的名字, 是我们要爬虫允许的域名地址 此时目录如下(db目录是后面加的数据库操作工具类的文件夹)在这里插入图片描述

    这里面我们要改几个地方来实现我们的功能。

    2.1.2.1 修改spider接口实现

    主要修改的内容有:url:开始爬虫的首页allow_domians:允许爬虫的网站域名def parse(self, response):这里处理爬虫返回的网页内容,抓取数据 第一次的url中要拼接一个16位的时间戳,类中提供了方法,后续的这个offset都是根据上一次返回的数据最后一个里面的offset来赋值即可。 这个spider类的主要内容如下:

    class tbmmSpider(Spider):
        # url = "https://www.csdn.net/api/articles?type=more&category=home&shown_offset="
        url = 'https://www.csdn.net/api/articles?type=more&category=newarticles&shown_offset='
        name = "csdnspider"
        allow_domians = ["www.csdn.net"]
        
        def get_time_stamp16(self):
            # 生成16时间戳   eg:1540281250399895    -ln
            datetime_now = datetime.datetime.now()
           
            # 10位,时间点相当于从1.1开始的当年时间编号
            date_stamp = str(int(time.mktime(datetime_now.timetuple())))
    
            # 6位,微秒
            data_microsecond = str("%06d"%datetime_now.microsecond)
    
            date_stamp = date_stamp+data_microsecond
            return int(date_stamp)
    
        def start_requests(self):
            curl = self.url + str(self.get_time_stamp16())
            yield Request(curl, headers=self.headers)    
    
        def parse(self, response):
            datas = json.dumps(response.text, ensure_ascii= False, indent=4, separators=(',', ': '))
           
            json_data = json.loads(datas)
            json_data = json_data.replace('null', '\"\"').replace(u'None', u'\"\"').replace(u'false', 'False').replace(u'true', 'True')
           
            dict = eval(json_data)
            articles = dict['articles']
            
            if articles and len (articles) > 0:
                for article in articles:
                    item = CsdnnewsItem()
                    item['avatar'] = article['avatar']
                    item['title'] = article['title']
                    item['category'] = article['category']
                    item['category_id'] = article['category_id']
                    item['channel'] = article['channel']
                    item['show_datetime'] = article['created_at']
                    item['cur_id'] = article['id']
                    item['user_name'] = article['user_name']
                    item['nickname'] = article['nickname']
                    item['user_url'] = article['user_url']
                    item['showtime'] = article['shown_time']
                    item['source_from'] = 'csdn'
                    item['summary'] = article['summary']
                    item['tag'] = article['tag']
                    item['type'] = article['type']
                    item['detail_url'] = article['url']
                    item['views_count'] = article['views']
                    item['comments_count'] = article['comments']
                    shown_offset = article['shown_offset']
                    yield item
            
                #如果datas存在数据则对下一页进行采集
                time.sleep(0.5)
                next_url = self.url + str(shown_offset)
                yield Request(next_url, headers=self.headers)    
    
    
    2.1.2.2 修改items.py文件

    声明接收抓取内容的item类属性 内容如下:

    
    class CsdnnewsItem(scrapy.Item):
        # define the fields for your item here like:
        
        # 头像
        avatar = scrapy.Field()
    
        # 标题
        title = scrapy.Field()
    
        # 分类文本
        category = scrapy.Field()
    
        # 分类id
        category_id = scrapy.Field()
    
        # 渠道
        channel = scrapy.Field()
    
        # 创建时间
        created_time = scrapy.Field()
    
        # 当前id
        cur_id = scrapy.Field()
    
        # 用户名
        user_name = scrapy.Field()
    
        # 作者昵称
        nickname = scrapy.Field()
    
        # 用户详情url
        user_url = scrapy.Field()
    
        # 展示时间
        showtime = scrapy.Field()
    
        # 展示时间,比如2018年8月、19小时前、2天前
        show_datetime = scrapy.Field()
        
        # 来源
        source_from = scrapy.Field()
        
        # 摘要
        summary = scrapy.Field()
    
        # 标签(多个标签以|分割)
        tag = scrapy.Field()
    
        # 类型(blog、news、article)
        type = scrapy.Field()
    
        # 详情url
        detail_url = scrapy.Field()
    
        # 阅读数量
        views_count = scrapy.Field()
    
        # 评论数量
        comments_count = scrapy.Field()
        
    
    
    2.1.2.3 修改pipeline.py文件

    实现保存数据到mysql数据库

    class CsdnnewsPipeline(object):
        def __init__(self):
            self.db = DBHelper()
    
    
        def process_item(self, item, spider):
            self.db.insert(item)
    
            return item
    
        def close_spider(self, spider):
           
    
    
    2.1.2.4 修改settings.py文件

    声明pymysql数据库连接信息等

    
    BOT_NAME = 'csdnnews'
    
    SPIDER_MODULES = ['csdnnews.spiders']
    NEWSPIDER_MODULE = 'csdnnews.spiders'
    
    #mysql-连接配置
    MYSQL_HOST = '127.0.0.1'
    MYSQL_DBNAME = 'voanews'
    MYSQL_USER = 'news'
    MYSQL_PASSWD ='123456'
    MYSQL_PORT = 3306
    
    # 下面这个要打开,否则无法通过pipe管道存储到数据库
    ITEM_PIPELINES = {<!-- -->
        'csdnnews.pipelines.CsdnnewsPipeline': 300,
    }
    
    
    2.1.2.5 修改dbhelper.py文件

    实现保存到数据库

    # -*- coding: utf-8 -*-
    import pymysql
    from twisted.enterprise import adbapi
    from scrapy.utils.project import get_project_settings  #导入seetings配置
    
    class DBHelper():
    
        def __init__(self):
            settings = get_project_settings()  #获取settings配置,设置需要的信息
    
            dbparams = dict(
                host=settings['MYSQL_HOST'],  #读取settings中的配置
                db=settings['MYSQL_DBNAME'],
                user=settings['MYSQL_USER'],
                passwd=settings['MYSQL_PASSWD'],
                charset='utf8',  #编码要加上,否则可能出现中文乱码问题
                cursorclass=pymysql.cursors.DictCursor,
                use_unicode=False,
            )
            #**表示将字典扩展为关键字参数,相当于host=xxx,db=yyy....
            dbpool = adbapi.ConnectionPool('pymysql', **dbparams)
            self.__dbpool = dbpool
    
        def connect(self):
            return self.__dbpool
    
        #插入数据
        def insert(self, item):
            #这里定义要插入的字段
           
            sql = "insert into news(avatar, title, category, category_id, channel,show_datetime,\
             cur_id, user_name, nickname, user_url, showtime, source_from, summary, tag, type, detail_url, views_count, comments_count)\
              values(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
            #调用插入的方法
            query = self.__dbpool.runInteraction(self._conditional_insert, sql, item)
            #调用异常处理方法
            query.addErrback(self._handle_error)
            return item
    
        #写入数据库中
        def _conditional_insert(self, canshu, sql, item):
            
            #取出要存入的数据,这里item就是爬虫代码爬下来存入items内的数据
            params = (item['avatar'], item['title'], item['category'], item['category_id'], item['channel'], 
            item['show_datetime'], item['cur_id'], item['user_name'], item['nickname'], item['user_url'], 
            item['showtime'], item['source_from'], item['summary'], item['tag'], item['type'], item['detail_url'], item['views_count'], item['comments_count'])
            canshu.execute(sql, params)
    
        #错误处理方法
        def _handle_error(self, failue):
            print('--------------database operation exception!!-----------------')
            print(failue)
    
        def __del__(self):
            try:
                self.__dbpool.close()
            except Exception as ex:
                print(ex)
                
    
    
    2.1.3 启动爬虫

    在启动前,先初始化mysql的表结构,源码中db目录有个init.sql文件,执行后会创建一个存储爬取内容的表结构,同时要把setting中配置的用户名,在mysql中创建相应的用户以及授权给刚才新建的表。不清楚的可以评论回复,这里不岔话题了。 我们在刚才的spider目录的同级路径,输入以下命令即可启动爬虫:

    scrapy crawl csdnspider

    2.1.4 源码下载

    本节结束,爬取csdn博文的源码下载:

    2.2、cnblog博客园

    2.2.1、页面分析

    我们打开博客园的java分类,地址是: 可以看到这个网站跟前面的csdn不一样的是,这个的文章列表内容是直接在源码里面的,这种是最容易爬取的,我们在页面右键查看源码内容如下:在这里插入图片描述

    刚好对应了页面的前两篇文章:

    在这里插入图片描述

    下面让我们来看下页面的文章列表布局:在这里插入图片描述

    所有的文章都是在一个id值为post_listdiv里面,每一个文章布局都是包裹在一个class属性值为post_itemdiv布局里面。

    我们再看下底部的翻页跳转导航内容:

    在这里插入图片描述

    翻页导航布局是在一个class属性值为pagerdiv里面,每一个a标签表示一页导航地址。

    找到页面的规律后,接下来让我们编写爬虫实现文章的提取。

    2.2.2、爬虫实现
    2.2.2.1、创建项目

    打开vscode终端定位到工程目录,例如d:/tmp/cnblog 输入:scrapy startproject cnblog 提示成功后,进入到cnblog目录cd cnblog 然后输入以下命令创建爬虫:scrapy genspider -t crawl cnblogspider www.cnblogs.com 其中cnblogspider 是爬虫类的名字,www.cnblogs.com 是我们要爬虫允许的域名地址 此时目录如下(db目录是后面加的数据库操作工具类的文件夹)。

    这里跟前面一节实现爬取csdn博文的爬虫不一样的是,在创建爬虫的时候,加了参数-t crawl,就是以crawl模板来创建一个继承自CrawlSpiderspider

    2.2.2.2、spider实现

    spider的内容如下: 其中start_urls 是代表要爬取的首页列表,这里选择了java、python、linux等分类; parse_item是我们处理数据的回调,这里解析页面提取文章各元素; rules是告诉爬虫应该如何提取翻页导航,这里是以xpath方式定位翻页导航元素,根据2.2.2.1节里面的页面分析很容易理解。

    
    class CnblogspiderSpider(CrawlSpider):
        name = 'cnblogspider'
        allowed_domains = ['www.cnblogs.com']
        start_urls = [
            'https://www.cnblogs.com/cate/java/',
            'https://www.cnblogs.com/cate/python/',
            'https://www.cnblogs.com/cate/job/',
            'https://www.cnblogs.com/cate/algorithm/',
            'https://www.cnblogs.com/cate/linux/',
            'https://www.cnblogs.com/cate/mysql/',
            'https://www.cnblogs.com/cate/cpp/',
            'https://www.cnblogs.com/cate/go/'
            ]
    
        rules = (
            Rule(LinkExtractor(restrict_xpaths=('//div[@id="pager_bottom"]/div[@id="paging_block"]/div[@class="pager"]/a', )),  callback='parse_item', follow=True),
        )
    
        
        def parse_item(self, response):
            for article in response.xpath('//div[@id="post_list"]/div[@class="post_item"]'):
                item = CnblogItem()
                try:
                    
                    item['title'] = article.xpath('./div[@class="post_item_body"]/h3/a[@class="titlelnk"]/text()').extract_first()
                    item['summary'] = article.xpath('./div[@class="post_item_body"]/p[@class="post_item_summary"]/text()').extract_first()
                    item['detail_url'] = article.xpath('./div[@class="post_item_body"]/h3/a[@class="titlelnk"]/@href').extract_first()
                    item['logo_url'] = article.xpath('./div[@class="post_item_body"]/p[@class="post_item_summary"]/a/img/@src').extract_first()
                    
                    item['source_from'] = '博客园'
                    item['show_datetime'] = article.xpath('./div[@class="post_item_body"]/p/div[@class="post_item_foot"]/text()').extract_first()
                    item['user_name'] = article.xpath('./div[@class="post_item_body"]/p/div[@class="post_item_foot"]/a/text()').extract_first()
                    item['nickname'] = article.xpath('./div[@class="post_item_body"]/p/div[@class="post_item_foot"]/a/text()').extract_first()
                    item['user_url'] = article.xpath('./div[@class="post_item_body"]/p[@class="post_item_summary"]/a/@href').extract_first()
                    item['cur_id'] = ''
    
                    item['views_count'] =  article.xpath('./div[@class="post_item_body"]/div[@class="post_item_foot"]/span[@class="article_view"]/a/text()').extract_first()
                    item['views_count'] = re.findall("\((\d*?)\)", item['views_count'])[0]
                    item['comments_count'] =  article.xpath('./div[@class="post_item_body"]/div[@class="post_item_foot"]/span[@class="article_comment"]/a/text()').extract_first()
                    item['comments_count'] = re.findall("\((\d*?)\)", item['comments_count'])[0]
                    print(item['views_count'])
                    print(item['comments_count'])
                except Exception as ex:
                    print(ex)
               
                yield item
    
    
    2.2.2.3、items实现

    跟前面2.1节爬取csdn的一样,定义了一样的元素,只不过不同的博客文章,所能提取的字段不一样,只是这里定义的一部分而已。这里就不重复贴代码了。

    2.2.2.4、pipeline、settings、dbhelper的实现

    这几个都跟2.1节爬取csdn的差不多,只是在dblhelper里面存储的字段不一样而已,具体直接看源码吧。

    2.2.3、启动爬虫

    如果已经按照2.1爬取csdn的章节里面初始化过mysql数据库了,这一步可以省略。

    在启动前,先初始化mysql的表结构,源码中db目录有个init.sql文件,执行后会创建一个存储爬取内容的表结构,同时要把setting中配置的用户名,在mysql中创建相应的用户以及授权给刚才新建的表。不清楚的可以评论回复,这里不岔话题了。

    我们在刚才的spider目录的同级路径,输入以下命令即可启动爬虫:

    scrapy crawl cnblogspider

    2.2.4、源码下载

    本节结束,爬取cnblog博客园文章的源码下载:

    2.3、51cto博客

    2.3.1 页面分析

    我们打开技术类的推荐分类:在这里插入图片描述

    2.3.2、启动爬虫

    如果已经按照2.1爬取csdn的章节里面初始化过mysql数据库了,这一步可以省略。

    在启动前,先初始化mysql的表结构,源码中db目录有个init.sql文件,执行后会创建一个存储爬取内容的表结构,同时要把setting中配置的用户名,在mysql中创建相应的用户以及授权给刚才新建的表。不清楚的可以评论回复,这里不岔话题了。

    我们在刚才的spider目录的同级路径,输入以下命令即可启动爬虫:

    scrapy crawl ctospider

    2.3.3、源码下载

    本节结束,爬取51CTO博客文章的源码下载:

    2.4、jobbole伯乐在线

    2.4.1 页面分析

    我们打开伯乐在线的全部文章页面: 可以看到底部有分页导航,是不是很爽…克制一点,以学习为目的,不要耍流氓哈,不要干坏事。在这里插入图片描述 创建工程、创建爬虫、编写spider等就不重复了,跟前面的一样一样的,直接看源码会更直接。

    2.4.2、启动爬虫

    如果已经按照2.1爬取csdn的章节里面初始化过mysql数据库了,这一步可以省略。

    在启动前,先初始化mysql的表结构,源码中db目录有个init.sql文件,执行后会创建一个存储爬取内容的表结构,同时要把setting中配置的用户名,在mysql中创建相应的用户以及授权给刚才新建的表。不清楚的可以评论回复,这里不岔话题了。

    我们在刚才的spider目录的同级路径,输入以下命令即可启动爬虫:

    scrapy crawl jobbolespider

    2.4.3、源码下载

    本节结束,爬取伯乐在线博客文章的源码下载:

    2.5、itpub博客(待续)

    2.5.1、页面分析

    我们打开itpub的linux专题:在这里插入图片描述 我们右键查看源码,可以看到文章内容就在源码中,只不过这个网站的翻页导航不是跟前面的一样有直接的第1页、第2页、下一页的形式,而是在底部有个“点击加载更多”的布局,其实也是一个a标签,跟其它的分页导航没有本质的区别。

    创建工程、创建爬虫、编写spider等就不重复了,跟前面的一样一样的,直接看源码会更直接。

    2.5.2、启动爬虫

    如果已经按照2.1爬取csdn的章节里面初始化过mysql数据库了,这一步可以省略。

    在启动前,先初始化mysql的表结构,源码中db目录有个init.sql文件,执行后会创建一个存储爬取内容的表结构,同时要把setting中配置的用户名,在mysql中创建相应的用户以及授权给刚才新建的表。不清楚的可以评论回复,这里不岔话题了。

    我们在刚才的spider目录的同级路径,输入以下命令即可启动爬虫:

    scrapy crawl itpubspider

    2.5.3、源码下载

    本节结束,爬取ITPUB博客文章的源码下载:

    2.6、oschina开源中国博客

    2.6.1、页面分析

    开源中国的博客就比较有意思,他的翻页比较隐藏,但是还是可以分析得到的。我们打开编程语言的首页,并且按F12打开调试模式查看Ajax过滤异步请求:在这里插入图片描述 可以看到这里是有异步请求获取内容的,并且从过滤的Ajax请求的内容一看便知,在当前分类(比如截图中的编程语言分类是classification=428609)定了的前提下,p=2就是表示获取第二页的数据了,type=ajax表示以异步的方式返回文章列表。

    再让我们看下源码,在当前页面右键查看源码,如下图:可以看到它的内容在源码里面的:在这里插入图片描述

    但是它页面上又看不到上一页、下一页、或者第1页,第2页之类的分页导航的布局。从下图可以看到,其实是有的,只不过它的布局元素都设置了显示属性为隐藏的:style="display: none",所以我们看不到。 这样我们就知道在crawl爬虫中如何获取爬虫所需下一页的布局元素了。在这里插入图片描述

    那还有个问题:oschina开源中国这个网站的博客页面,跟前面的几个可以通过页面翻页导航自动爬取同系列的博客页面不一样的是,这里没有告诉我们它的最后一页是多少,如何判断呢?我们这里采取一个策略:如果当前这次请求,没有返回任何博客文章内容了,就认为到最后一页了。

    2.6.2、爬虫实现

    ok,前面分析过页面结构、翻页导航定位、判断最后一页的策略了,这里就具体实现爬虫模块。

    这里我们把爬虫访问的首页定为p=1,链接就是前面2.6.1分析的Ajax异步请求里面的内容,只是把p=2改为p=1就是访问第一页了。 下一页的定位规则也很容易理解,通过XPath定位到2.6.1分析的那个隐藏的翻页的a标签即可。

    start_urls = ['https://www.oschina.net/blog/widgets/_blog_index_recommend_list?classification=0&amp;type=ajax&amp;p=1']
    
    rules = (
        Rule(LinkExtractor(restrict_xpaths=('//p[@class="pagination"]/a[contains(@class, "pagination__next")]', )),  callback='parse_item', follow=True),
    )
    
    

    解析文字列表的方法如下:这个直接看代码就行了,主要是根据XPath提取我们需要的字段,如果对XPath不熟悉,可以参考我的另一篇文章有详细介绍使用示例: 的2.1.3节有介绍。

    def parse_item(self, response):
        for article in response.xpath('//div/div[contains(@class, "blog-item")]'):
            item = OschinaItem()
            try:
                
                item['title'] = article.xpath('./div[@class="content"]/a[@class="header"]/@title').extract_first()
                item['summary'] = article.xpath('./div[@class="content"]/div[@class="description"]/p/text()').extract_first()
                item['detail_url'] = article.xpath('./div[@class="content"]/a[@class="header"]/@href').extract_first()
                item['source_from'] = '开源中国'
                item['show_datetime'] = article.xpath('./div[@class="content"]/div[@class="extra"]/div/div[2]/text()').extract_first()
                item['user_name'] = article.xpath('./div[@class="content"]/div[@class="extra"]/div/div[1]/a/text()').extract_first()
                item['nickname'] = article.xpath('./div[@class="content"]/div[@class="extra"]/div/div[1]/a/text()').extract_first()
                item['user_url'] = article.xpath('./div[@class="content"]/div[@class="extra"]/div/div[1]/a/@href').extract_first()
                item['cur_id'] = article.xpath('./@data-id').extract_first()
    
                item['views_count'] = article.xpath('./div[@class="content"]/div[@class="extra"]/div/div[3]/text()').extract_first()
                view_count_str = str(item['views_count'])
    
                # 因为页面上的浏览数,这个网站返回的是2k,100之类的,要统一转为整型存储到数据库
                if view_count_str.find('K') &gt; -1:
                    view_count_str = view_count_str.lstrip().rstrip()   
                    item['views_count'] = int(float(view_count_str.replace('K',''))*1000.0)
                if view_count_str.find('w') &gt; -1:
                    item['views_count'] = str(float(view_count_str.replace('w',''))*10000.0)
                
                item['comments_count'] = article.xpath('./div[@class="content"]/div[@class="extra"]/div/div[4]/a/text()').extract_first()
                
            except Exception as ex:
                print(ex)
           
            yield item
    
    

    OK,主要的就上面这个代码,其它的跟前面章节的都大同小异,直接看源码即可。

    2.6.3、启动爬虫

    如果已经按照2.1爬取csdn的章节里面初始化过mysql数据库了,这一步可以省略。

    在启动前,先初始化mysql的表结构,源码中db目录有个init.sql文件,执行后会创建一个存储爬取内容的表结构,同时要把setting中配置的用户名,在mysql中创建相应的用户以及授权给刚才新建的表。不清楚的可以评论回复,这里不岔话题了。

    我们在spider目录的同级路径,输入以下命令即可启动爬虫:

    scrapy crawl oschinaspider

    2.6.4、源码下载

    本节结束,爬取OSChina开源中国博客文章的源码下载:

    全部内容完毕,这里只是总结下自己最近学习scrapy爬虫的几个实践,通过这几个实践,一般的类似需求应该都可以搞定,当然这里没有涉及到反爬虫厉害的站点的处理,比如浏览器header伪装、ip代理、爬虫时间间隔等,后续有机会再实践下。 本文内容如有错误,恳请斧正,如有更好的技术,欢迎指点一二,谢谢。

    3、参考资料

    [1]: [2]: [3]: [4]: [5]: [6]:

    转载于:https://www.cnblogs.com/xiaocy66/p/10589254.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本程序用java编写,运行的时候需要JDK1.5或以上环境,无需安装。程序通过分析博客园博 客源码来生成一些必要的数据,可能在以后使用当中出现爬取不了的情况,可能是博客园的源码 结构修改了。程序只是用于学习之用,严禁用于非法目的而照成博客园服务器过载。 由于生成PDF的时候需要依赖字库,所以在打包程序的时候把一些必要的字库已经放到程序中 去了。可能在生成一些PDF文件的时候出现乱码问题,那是因为里面缺少需要的字库,如遇到这 个问题,请和本人联系:wyphao.2007@163com fonts文件夹是生成pdf文件依赖的字体库,如果生成的pdf文件是乱码,说明缺少相关的字体。 #################################################### 程序功能: 1、支持输入博客博客用户名针对性下载 2、支持选择保存下载的文件 保存的结构目录为: 选择的保存路径\博客园用户名\pdf 生成的PDF文件保存路径 选择的保存路径\博客园用户名\doc 生成的DOC文件保存路径 选择的保存路径\博客园用户名\txt 生成的TXT文件保存路径 3、支持获取用户博客信息 4、支持显示用户所有的帖子列表 5、可以自己选择需要下载的帖子,有全选、反选、重置按钮 6、支持下载的文件保存为 pdf、doc、txt三种格式 7、生成的pdf、doc文件支持图片 8、支持进度显示 #################################################### 制作时间:2012年07月21日 - 2012年07月21日 制 作:w397090770 个人博客:http://blog.csdn.net/w397090770 Email :wyphao.2007@163.com 版权所有,翻版不究 ####################################################
好的,这是一个比较复杂的任务,需要一些具体的步骤来完成。我可以提供一些大致的思路和代码参考。 1. 首先需要安装 Scrapy 和 SQLite3,可以使用 pip 命令进行安装: ``` pip install scrapy pip install sqlite3 ``` 2. 创建 Scrapy 项目和 Spider 在终端中进入工作目录,执行以下命令创建 Scrapy 项目: ``` scrapy startproject beike ``` 然后使用以下命令在项目中创建 Spider: ``` cd beike scrapy genspider beike_spider ke.com ``` 这里的 `beike_spider` 是你自己定义的 Spider 名称,`ke.com` 是你要爬取的网站域名。 3. 编写 Spider 代码 在 `beike/spiders` 目录下找到 `beike_spider.py` 文件,根据需求修改代码。以下是一个简单的示例: ```python import scrapy import sqlite3 class BeikeSpider(scrapy.Spider): name = 'beike_spider' allowed_domains = ['ke.com'] start_urls = ['https://nb.ke.com/ershoufang/'] def parse(self, response): # 获取页面中所有房屋信息的链接 house_urls = response.css('.sellListContent li .title a::attr(href)').extract() for url in house_urls: yield scrapy.Request(url, callback=self.parse_house) def parse_house(self, response): # 解析房屋信息 title = response.css('.title-wrapper .main::text').extract_first().strip() price = float(response.css('.price .total::text').extract_first()) area = float(response.css('.area .mainInfo::text').extract_first()) unit_price = float(response.css('.unitPrice .unitPriceValue::text').extract_first()) # 存储数据库 conn = sqlite3.connect('beike.db') cursor = conn.cursor() cursor.execute('CREATE TABLE IF NOT EXISTS houses (title TEXT, price FLOAT, area FLOAT, unit_price FLOAT)') cursor.execute('INSERT INTO houses (title, price, area, unit_price) VALUES (?, ?, ?, ?)', (title, price, area, unit_price)) conn.commit() conn.close() ``` 这个 Spider 的作用是爬取宁波贝壳网二手房页面中的所有房屋信息,解析房屋标题、价格、面积和单价,并将其存储到 SQLite3 数据库中。 4. 配置数据库 在工作目录下创建一个空的 SQLite3 数据库文件 `beike.db`。 5. 运行 Spider 使用以下命令运行 Spider: ``` scrapy crawl beike_spider ``` Spider 会自动爬取网站并将数据存储数据库中。 以上是一个简单的示例,具体实现可能会有所差异。如果遇到问题,可以参考 Scrapy 和 SQLite3 的官方文档进行查阅。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值