历时两天的第一个多层网页爬虫

之前因为学习上的一些需要,也写了一两个爬虫,都是爬单页面的,或者只是简单的循环页面的。在因为论文的事情弄的焦头烂额的时候,忽然想学学scrapy换个头脑,然后就花了一天的时间看看scrapy的官方文档,算是对其有个大概的了解,但是当真正开始完全的写一个爬虫的时候还是感受到:买家秀和买家秀的区别了。

其实这个爬虫在网上都可以搜到很多:爬妹子图网站的所有图片。之前也有写过一个,但是只爬了第一页的图片。昨天想着:我要全部!!!废话不多说,先上代码。

# -*- coding: utf-8 -*-
import scrapy
from tupian.items import TupianItem
from scrapy.spiders import CrawlSpider
class MeizituSpider(CrawlSpider):
    name = "meizitu"
    allowed_domains = ["meizitu.com"]
    start_urls = ['http://www.meizitu.com/a/list_1_1.html']
    def parse(self, response):
        items=[]
        print(response.url)
        infos = response.xpath("//ul[@class='wp-list clearfix']/li/div/div/a")
        for info in infos:
            item=TupianItem()
            page_link = info.xpath('@href')[0].extract()
            print(page_link)
            item['list_url'] = response.url
            item['page_link']= page_link
            items.append(item)
        for item in items:
            yield scrapy.Request(url=item['page_link'],meta={'item_1': item},callback=self.parse_page)
        for i in range(2,92):
            all_pages = 'http://www.meizitu.com/a/list_1_%s.html' % i
            yield scrapy.Request(url=all_pages, callback=self.parse)
    def parse_page(self,response):
        items = response.meta['item_1']
        infos= response.xpath('//div[@class="postContent"]/div/p/img')
        print(len(infos))
        for info in infos:
            item=TupianItem()
            image_names =info.xpath('@alt')[0].extract()
            images_urls= info.xpath('@src')[0].extract()
            item['pic'] = image_names
            item['images_urls'] = images_urls
            item['list_url'] = items['list_url']
            item['page_link'] = items['page_link']
            print(item)
            yield item

因为这次爬的是多层页面的数据,就涉及到数据的传递,我一直没有搞明白到底是怎么来传递的,自己琢磨了一天,抓狂的不要不要的。
嘴勤能问出金马驹的,我在简书上认识的一位老师@向右奔跑 所建的微信群里吼了一嗓子,霹雳一声震天响,来了一位程司机,带我起飞,带我嘿嘿嘿。为我特意写了一次这个爬虫,一直折腾到一点多。再次感谢感谢。

一点点分析:

import scrapy
from tupian.items import TupianItem
from scrapy.spiders import CrawlSpider
class MeizituSpider(CrawlSpider):
    name = "meizitu"
    allowed_domains = ["meizitu.com"]  #这行的意义:不是这个域名类的网址都不爬。不然就要在parse的时候加上一个 don't filter=True
    start_urls = ['http://www.meizitu.com/a/list_1_1.html'] #显而易见:起始页面

关键的时刻来了:多层页面怎么传递数据?
首先要理清思路:

《历时两天的第一个多层网页爬虫》 Paste_Image.png

在我们要解析的第一页里,有30个如箭头所示的子链接,每一个子链接下面又有7-8张这样的图片,这才是我们想要的。要怎么把弄出来?

《历时两天的第一个多层网页爬虫》 Paste_Image.png

我们先理清楚:
(1)http://www.meizitu.com/a/list_1_1.html 这样的页面总共有92个
(2)每个上面的网址又包含30个的子链接 (最后一页不满30个,无所谓)
(3)每个子链接下面又有8张我们想要的图片
所以总数就是总数就是: 92308

首先:我们把每个页面下的30个链接给解析出来

 def parse(self, response): 
        items=[]  #首先实例化一个空列表用来传递数据
        print(response.url) # 看一下我们解析其实网页出来的数据
        infos = response.xpath("//ul[@class='wp-list clearfix']/li/div/div/a")  #找出子链接的总节点,返回的是一个列表
        for info in infos:#对列表进行循环
            item=TupianItem() 
            page_link = info.xpath('@href')[0].extract() #取出子链接
            print(page_link)
            item['list_url'] = response.url # 这一个要不要都可以,只是为了显示出逻辑关系
            item['page_link']= page_link #将子链接的值添加到item对应的字典里
            items.append(item) #最后将所有的子链接的网址添加到最开始创建的快递盒子里
        for item in items:
            yield scrapy.Request(url=item['page_link'],meta={'item_1': item},callback=self.parse_page) # 现在来拆开快递, 调用self.parse_page函数来解析出每个子链接里面的8张图片,注意子链接是“page_link"。

重点是数据怎么传递的,为了这点,我花了一天的时间还没明白。

meta是一个内置的参数,类型是字典,meta={‘item_1’: item} 这个的意思就是创建以‘item_1’为key,以item为value的字典。因为是在循环里,所以每次赋值一个item的时候,就调用一次具体解析出8张图片的函数。因为我们的items有两个key,我们要的是item[‘page_link’]这个。

这步想明白就简单了,因为总共有92个网页,通过观察有以下的变化模式:

        for i in range(2,92):
            all_pages = 'http://www.meizitu.com/a/list_1_%s.html' % i
            yield scrapy.Request(url=all_pages, callback=self.parse)

最后一步就是构造解析8张图片的函数了

    def parse_page(self,response):
        items = response.meta['item_1']# 我对这句的理解是,跟上面的函数一样,只不过这次的起始页面换成了meta里的item
        infos= response.xpath('//div[@class="postContent"]/div/p/img') #同样,解析出每个图片和名字的节点
        print(len(infos))
        for info in infos:
            item=TupianItem()
            image_names =info.xpath('@alt')[0].extract()#取出标题
            images_urls= info.xpath('@src')[0].extract()#取出图片
            item['pic'] = image_names #实例化
            item['images_urls'] = images_urls #实例化
            item['list_url'] = items['list_url'] #实例化
            item['page_link'] = items['page_link'] #实例化
            print(item)
            yield item

pipline

import pymysql  #数据库我不懂,照着网上的教程写了一下。这里吹不出来  ~~。。~~
def dbHandle():
    conn = pymysql.connect(
        host = "localhost",
        user = "名字",
        passwd = "密码",
        charset = "utf8",
        use_unicode = False
    )
    return conn

class TupianPipeline(object):
    def process_item(self, item, spider):
        dbObject = dbHandle()
        cursor = dbObject.cursor()
        sql = "insert into meizitu.t_meizitu(list_url,page_link,images_urls,pic) value (%s,%s,%s,%s)"
        try:
            cursor.execute(sql, (item['list_url'], item['page_link'],  item['images_urls'], item['pic']))
            cursor.connection.commit()
        except BaseException as e:
            print("错误在这里>>>>", e, "<<<<<<错误在这里")
            dbObject.rollback()
        return item

item

import scrapy


class TupianItem(scrapy.Item):
    images_urls = scrapy.Field()
    pic = scrapy.Field()
    image = scrapy.Field()
    page_link = scrapy.Field()
    list_url = scrapy.Field()

跟单页面的爬虫相比,最大的不同就是在数据传递的方面,要想清楚,你要传什么参数给下一个解析函数。传递的方法其实已经固定:定义一个空列表,将所要传递的内容当成字典传递下去,而在下一个解析函数里,首先就是解析从上个函数传递下来的内容。
感谢程老师,@Mr_Cxy

    原文作者:谁占了我的一年的称号
    原文地址: https://www.jianshu.com/p/9a644e9d6528
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞