分布式爬取顶点小说全站内容

7 篇文章 0 订阅
2 篇文章 0 订阅

这是一个简单的分布式爬虫,网站其实并不复杂,文章主要为了写一下分布式的布局。

首先使用命令 scrapy genspider -t crawl “爬虫名”  网址,创建一个爬虫。然后添加代码 

from scrapy_redis.spiders import RedisCrawlSpider

引入RedisCrawlSpider,并让爬虫继承于此。删除start_urls,并在rules中添加所需要的url的正则表达的:

class NovelSpiderSpider(RedisCrawlSpider):
    name = 'novel_spider'

    redis_key = 'novel_spider:start_urls'

    list_page_lin=LinkExtractor(allow=(r'https://www.23us.so/list/.*?html'))
    novel_page=LinkExtractor(allow=(r'https://www.23us.so/xiaoshuo/\d+.html'))
    chapter_page=LinkExtractor(allow=(r'https://www.23us.so/files/article/html/\d+/\d+/index.html'))
    contents_page=LinkExtractor(allow=(r'https://www.23us.so/files/article/html/\d+/\d+/\d+.html'))
    # print(novel_page)


    rules = (
        Rule(list_page_lin,follow=True),
        Rule(novel_page,callback='parse_intro',follow=True),
        Rule(chapter_page,follow=True,),
        Rule(contents_page,callback='parse_item',follow=True)
    )

follow=True或者follow=False,表示是否对网页进行深度抓取,因为scrapy_redis中本身存在去重的机制,所以我选择的都是True。然后在callback的回调解析中解析你所需要的内容,我分了两个库存储,一个存放内容介绍,一个存放具体的章节和内容。

def parse_item(self, response):
    print("===============================")

    # print(response.url)
    item = XiaoshuoItem()
    item['rr']="21"
    # item['url']=response.url
    item['n_name'] = response.xpath('//*[@id="amain"]/dl/dt/a[3]/text()').extract_first()
    item['c_name'] = response.xpath('//*[@id="amain"]/dl/dd[1]/h1/text()').extract_first()
    print(response.xpath('//*[@id="amain"]/dl/dd[1]/h1/text()').extract_first())
    ret = ''
    contents = response.xpath('//dd[@id="contents"]/text()').extract()
    for i in contents:
        ret += i
    item['c_contents'] = ret

    yield item

存储的时候由于是分连个库存储的,需要区分内容,所以我加了一个隐藏的字段“rr”,在pipeline中判断本字段的内容或者格式来区分存储的库,其实使用if isinstance(item,XiaoshuoItem),这样判断也可以,但是数据多的时候可能会出现问题,所以我使用了隐藏字段,字段之作判断,并不保存。

数据的存储,我把书本简介存到了MongoDB中,把书的内容存到了mysql中,当然其实所有内容存到redis中会更加快点,但是我还是选择了mysql,没啥,就是习惯了。我在存mysql的时候,每个小说创建了一个表,表名称就是小说名

class DingdianxiaoshuoPipeline(object):
    def __init__(self):
        self.conn=pymysql.connect(
            host=MYSQL_HOST,
            port=MYSQL_PORT,
            user=MYSQL_USER,
            passwd=MYSQL_PASSWORD,
            db=MYSQL_DB,
        )
        self.cursor=self.conn.cursor()


    def process_item(self, item, spider):
        # table_name = item['n_name']
        if type(item['rr'])==str:
            creat_table='CREATE TABLE IF NOT EXISTS {} (novel_chapter varchar(256),chapter_contents varchar(10000))'.format(item['n_name'])
            self.cursor.execute(creat_table)
            data=[(item['c_name'],item['c_contents']),]
            sql="INSERT INTO {} (novel_chapter,chapter_contents) VALUES (%s,%s)".format(item['n_name'])
            self.cursor.executemany(sql,data)
            self.conn.commit()
            return item
        else:
            return item

整体的框架大约就是这样,我运行了一下午,并未见报错。但是为了保险起见,我还是加入了动态代理池和随机User-Agent表示对网站创作者的尊重,由于数量太大,并没有抓取完成。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值