1. 程式人生 > >Scrapy爬蟲框架學習

Scrapy爬蟲框架學習

需求 項目 創建 tps http 分享圖片 contains 創建項目 parse

一、Scrapy框架簡介

1. 下載頁面
2. 解析
3. 並發
4. 深度

二、安裝

linux下安裝    
    pip3 install scrapy
    
windows下安裝
    a.pip3 install wheel
    b.下載twisted和pywin32 http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
    c.進入下載目錄
         執行pip3 install Twisted-18.7.0-cp36-cp36m-win_amd64.whl     #cp36為適合python3.6
執行pip3 install pywin32-224-cp36-cp36m-win_amd64.whl   d.pip3 install scrapy e.下載並安裝pywin32:https://sourceforge.net/projects/pywin32/files/ #找到適合本機python版本的64位

三、Scrapy整體架構圖

  3.1 Scrapy使用Twisted異步網絡庫來處理網絡通訊

技術分享圖片

  3.2 各個主要文件說明

  spiders(蜘蛛)文件夾:如ip138.com

name    #不能省略,最好不要修改
starts_urls #起始url allowed_domains #爬取允許域名列表,起始url不受影響。網頁中的外鏈受此限制

四、基本使用

1. 指定初始url
2. 解析器響應內容
    - 給調度器
    - 給item:pipeline;用於做格式化;持久化

基本步驟:
a:scrapy startproject 項目名   #創建項目
b:進入項目目錄
c:scrapy genspider baidu www.baidu.com  #創建start_url
d:打開項目名\spiders\baidu.py進行編輯
e:scrapy crawl baidu    
#執行,加--nolog可以不顯示日誌,如果沒有內容顯示,可能此IP已經有防爬機制,可換個不知名ip試試

五、篩選器

  5.1 Selector介紹

  在scrapy中,可以使用Selector篩選器,代替BeautifulSoup

  在scrapy項目裏的spiders文件裏的baidu.py爬蟲文件編輯,導入Selecotr模塊

from scrapy.selector import Selector

  5.2 Selector(response=response).xpath()基本用法

//        #表示子子孫孫,即所有
.//        #當前對象的子孫中
/            #兒子
/div        #兒子中的div標簽
//div[@id]  #所有標簽含有id的div標簽
/div[@id=i1]    #兒子中的div且id =‘i1‘的標簽
obj.extract()        #列表中每一個對象轉換成字符串 ==>返回的是列表
obj.extract_first()  #列表中每一各對象轉換成字符串==>返回的是列表中第一個元素
//div/text()        #獲取所有div標簽裏的文本==》返回的是列表,元素是對象
//a/@href           #獲取所有a標簽裏的url==》返回的是列表,元素是對象
//a[starts-with(@href,"link")]    #獲取所有a標簽,並且href屬性是以link開頭的
//a[re:test(@href,"/sitehome/p/\d+")]/@href   #正則,獲取所有a標簽屬性href符合/sitehome/p/數字的
//div[@id=i1][@href=‘‘xx]   #[][]且的意思,即所有含有id=‘i1‘且href=‘xxx‘的div標簽
//a[contains(@href, "link")]    #所有href字段包含link字符串的a標簽

  5.3 簡單示例

  需求:在www.ip138.com網站裏,打印如下a標簽的文本內容和url地址

技術分享圖片

  在爬蟲文件(baidu.py)裏的parse類方法裏編輯 

技術分享圖片
# -*- coding: utf-8 -*-
import scrapy
from scrapy.selector import Selector

class BaiduSpider(scrapy.Spider):
    name = baidu
    allowed_domains = [ip138.com]
    start_urls = [http://www.ip138.com/]

    def parse(self, response):
        #請求該頁面下所有a標簽==》列表,每個元素都是對象
        #找到div標簽裏有class=mod-guide屬性下的所有子孫a標簽裏文本內容
        text_obj_list = Selector(response=response).xpath(//div[@class="module mod-guide"]//a/text())

        # 找到div標簽裏有class=mod-guide屬性下的所有子孫a標簽裏url
        url_obj_list = Selector(response=response).xpath(//div[@class="module mod-guide"]//a/@href)

        #將列表中對象轉化成列表中字符串
        text_str_list = text_obj_list.extract()
        url_str_list = url_obj_list.extract()

        for a_text,a_url in zip(text_str_list,url_str_list):
            print(a_text,a_url)
代碼

  如何運行代碼?

在cmd窗口,進入項目目錄,運行scrapy  crawl  baidu

  5.4 獲取當前網頁中的所有頁碼實例

  需求:獲取博客園裏的首頁頁碼url

技術分享圖片

  

  在爬蟲文件(ip138.py)裏的parse類方法裏編輯

技術分享圖片
# -*- coding: utf-8 -*-
import scrapy
from scrapy.selector import Selector

class Ip138Spider(scrapy.Spider):
    name = ip138
    allowed_domains = [www.cnblogs.com]
    start_urls = [https://www.cnblogs.com/]

    urls_set = set()

    def parse(self, response):
        # text_obj_list = Selector(response=response).xpath(‘//div[@class="module mod-guide"]//a/text()‘)
        # url_obj_list = Selector(response=response).xpath(‘//div[@class="module mod-guide"]//a/@href‘)
        #
        # text_str_list = text_obj_list.extract()
        # url_str_list = url_obj_list.extract()
        #
        # for text,url in zip(text_str_list,url_str_list):
        #     print(text,url)

        #獲取當前頁裏的所有頁碼的url對象列表
        url_obj_list = Selector(response=response).xpath(//div[@class="pager"]/a/@href)
        ##或者2: starts-with(@屬性,‘值開頭‘)
        #url_obj_list = Selector(response=response).xpath(‘//a[starts-with(@href,"/sitehome/p/")]/@href‘)
        ##或者3:正則表達式固定用法re:test(@屬性值,"正則表達式")
        #url_obj_list = Selector(response=response).xpath(‘//a[re:test(@href,"/sitehome/p/\d+")]/@href‘)

        #將對象列表轉換成字符串列表
        url_str_list = url_obj_list.extract()
        for url in url_str_list:
            print(url)

            #1.通過集合去除重復url
            #2.使用加密的MD5存儲url,好處:加密和等長
            url_md5 = self.my_md5(url)
            if url_md5 not in self.urls_set:
                self.urls_set.add(url_md5)
                print(url_md5)
            else:
                print(%s已經存在%url_md5)

    def my_md5(self,url):
        import hashlib
        obj = hashlib.md5()
        obj.update(bytes(url,encoding=utf-8))
        return obj.hexdigest()
代碼

  5.5 獲得當前網頁裏的頁碼自動請求爬取實例

  需求:自動爬取博客園的所有頁碼(基於5.4案例的基礎)

技術分享圖片

  

  在爬蟲文件(ip138.py)裏的parse類方法裏編輯

技術分享圖片
# -*- coding: utf-8 -*-
import scrapy
from scrapy.selector import Selector
from scrapy.http import Request

class Ip138Spider(scrapy.Spider):
    name = ip138
    allowed_domains = [www.cnblogs.com]
    start_urls = [https://www.cnblogs.com/]

    urls_set = set()

    def parse(self, response):

        #獲取當前頁裏的所有頁碼的url對象列表
        url_obj_list = Selector(response=response).xpath(//div[@class="pager"]/a/@href)
        ##或者2: starts-with(@屬性,‘值開頭‘)
        #url_obj_list = Selector(response=response).xpath(‘//a[starts-with(@href,"/sitehome/p/")]/@href‘)
        ##或者3:正則表達式固定用法re:test(@屬性值,"正則表達式")
        #url_obj_list = Selector(response=response).xpath(‘//a[re:test(@href,"/sitehome/p/\d+")]/@href‘)

        #將對象列表轉換成字符串列表
        url_str_list = url_obj_list.extract()
        for url in url_str_list:

            #1.通過集合去除重復url
            if url not in self.urls_set:
                #print(url)
                self.urls_set.add(url)
                #拼接完整的url地址
                full_url = self.start_urls[0] + url
                #將url頁碼傳給調度器去請求,並將下載的結果交給parse方法,yield的作用是將請求放入調度器
                yield Request(url=full_url,callback=self.parse)

            for url in self.urls_set:
                print(url)
代碼

  在setting.py中結尾新增一行DEPTH_LIMIT=1來指定遞歸的層次,默認是0,所有層次

  實例中關鍵點概括

@href    #取屬性值
starts-with(@href,"xx")   #屬性href的值以xx開始
re:test(@href,"/sitehome/p/\d+")   #正則re:test固定搭配
yield Request(url=full_url,callback=self.parse)   #交給調度器

六、item,pipeline使用

  6.1 需求:將博客園的文章標題和url保存到一個文件a.txt文件裏。

     各文件代碼如下:

技術分享圖片
# -*- coding: utf-8 -*-
import scrapy
from scrapy.selector import Selector
from scrapy.http import Request
from .. import items

class Ip138Spider(scrapy.Spider):
    name = ip138
    allowed_domains = [www.cnblogs.com]
    start_urls = [https://www.cnblogs.com/]

    urls_set = set()

    def parse(self, response):

        #獲取當前頁面裏的標題和url==>返回字符串
        title_str_list = Selector(response=response).xpath(//a[@class="titlelnk"]/text()).extract()
        href_str_list = Selector(response=response).xpath(//a[@class="titlelnk"]/@href).extract()

        for title_str,href_str in zip(title_str_list,href_str_list):
            #print(title_str,‘   ‘,href_str)
            
            #此處的參數title,和href來自於items.py文件裏類Cnblogs裏的屬性
            item_obj = items.Cnblogs(title=title_str,href=href_str)

            #將item對象傳遞給pipelines
            yield item_obj



        #獲取當前頁裏的所有頁碼的url對象列表
        page_obj_list = Selector(response=response).xpath(//div[@class="pager"]/a/@href)
        ##或者2: starts-with(@屬性,‘值開頭‘)
        #page_obj_list = Selector(response=response).xpath(‘//a[starts-with(@href,"/sitehome/p/")]/@href‘)
        ##或者3:正則表達式固定用法re:test(@屬性值,"正則表達式")
        #page_obj_list = Selector(response=response).xpath(‘//a[re:test(@href,"/sitehome/p/\d+")]/@href‘)

        #將對象列表轉換成字符串列表
        page_str_list = page_obj_list.extract()
        for url in page_str_list:

            #1.通過集合去除重復url
            if url not in self.urls_set:
                self.urls_set.add(url)
                print(url)

                #拼接完整的url地址
                full_url = self.start_urls[0] + url
                #將url頁碼傳給調度器去請求,並將下載的結果交給parse方法,yield的作用是將請求放入調度器
                yield Request(url=full_url,callback=self.parse)
ip138.py文件 技術分享圖片
# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class Cnblogs(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field()
    href = scrapy.Field()
items.py文件 技術分享圖片
# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don‘t forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html


class Day0310Pipeline(object):
    def process_item(self, item, spider):
        content = "%s    %s\n"%(item[title],item[href])
        f = open(a.json,a)
        f.write(content)
        f.close()
        # return item
pipelines.py文件 技術分享圖片
ITEM_PIPELINES = {
   day0310.pipelines.Day0310Pipeline: 300,
}
setting.py文件

  6.2 實例中關鍵點概括

#items.py文件中
class Cnblogs(scrapy.Item):     
    title = scrapy.Field()
    href = scrapy.Field()

#ip138.py文件中
from .. import items
item_obj = items.Cnblogs(title=title_str,href=href_str)   #此處的參數title,和href來自於items.py文件裏類Cnblogs裏的屬性

yield item_obj        #將item對象傳遞給pipelines

#pipelines.py文件中,可對收集到的數據進行存儲
class Day0310Pipeline(object):
    def process_item(self, item, spider):   #item為ip138.py文件裏的對象化的數據,spider為來自哪只蜘蛛對象
        content = "%s    %s\n"%(item[title],item[href])
        f = open(a.json,a)
        f.write(content)
        f.close()

#setting.py文件中註冊下pipelines的類
ITEM_PIPELINES = {
   day0310.pipelines.Day0310Pipeline: 300,
}
數字越高越優先

Scrapy爬蟲框架學習