python之路 - 爬蟲

網絡爬蟲(又被稱爲網頁蜘蛛,網絡機器人,在FOAF社區中間,更常常的稱爲網頁追逐者),是一種按照必定的規則,自動地抓取萬維網信息的程序或者腳本。另一些不常使用的名字還有螞蟻、自動索引、模擬程序或者蠕蟲html

Scrapy

Scrapy是一個爲了爬取網站數據,提取結構性數據而編寫的應用框架。 其能夠應用在數據挖掘,信息處理或存儲歷史數據等一系列的程序中。python

其最初是爲了頁面抓取 (更確切來講, 網絡抓取 )所設計的, 也能夠應用在獲取API所返回的數據(例如 Amazon Associates Web Services ) 或者通用的網絡爬蟲。Scrapy用途普遍,能夠用於數據挖掘、監測和自動化測試。正則表達式

Scrapy 使用了 Twisted異步網絡庫來處理網絡通信。總體架構大體以下網絡

Scrapy主要包括瞭如下組件:
  引擎(Scrapy)    用來處理整個系統的數據流處理, 觸發事務(框架核心)
   調度器(Scheduler)    用來接受引擎發過來的請求, 壓入隊列中, 並在引擎再次請求的時候返回. 能夠想像成一個URL(抓取網頁的網址或者說是連接)的優先隊列, 由它來決定下一個要抓取的網址是什麼, 同時去除重複的網址
   下載器(Downloader)    用於下載網頁內容, 並將網頁內容返回給蜘蛛(Scrapy下載器是創建在twisted這個高效的異步模型上的)
   爬蟲(Spiders)    爬蟲是主要幹活的, 用於從特定的網頁中提取本身須要的信息, 即所謂的實體(Item)。用戶也能夠從中提取出連接,讓Scrapy繼續抓取下一個頁面
   項目管道(Pipeline)    負責處理爬蟲從網頁中抽取的實體,主要的功能是持久化實體、驗證明體的有效性、清除不須要的信息。當頁面被爬蟲解析後,將被髮送到項目管道,並通過幾個特定的次序處理數據。
   下載器中間件(Downloader Middlewares)    位於Scrapy引擎和下載器之間的框架,主要是處理Scrapy引擎與下載器之間的請求及響應。
   爬蟲中間件(Spider Middlewares)    介於Scrapy引擎和爬蟲之間的框架,主要工做是處理蜘蛛的響應輸入和請求輸出。
   調度中間件(Scheduler Middewares)    介於Scrapy引擎和調度之間的中間件,從Scrapy引擎發送到調度的請求和響應。

Scrapy運行流程大概以下: 架構

  1. 引擎從調度器中取出一個連接(URL)用於接下來的抓取
  2. 引擎把URL封裝成一個請求(Request)傳給下載器
  3. 下載器把資源下載下來,並封裝成應答包(Response)
  4. 爬蟲解析Response
  5. 解析出實體(Item),則交給實體管道進行進一步的處理
  6. 解析出的是連接(URL),則把URL交給調度器等待抓取

1、安裝併發

1 pip install Scrapy

自動建立目錄:框架

project_name/
   scrapy.cfg
   project_name/
       __init__.py
       items.py
       pipelines.py
       settings.py
       spiders/
           __init__.py

文件說明:dom

  • scrapy.cfg  項目的配置信息,主要爲Scrapy命令行工具提供一個基礎的配置信息。(真正爬蟲相關的配置信息在settings.py文件中)
  • items.py    設置數據存儲模板,用於結構化數據,如:Django的Model
  • pipelines    數據處理行爲,如:通常結構化的數據持久化
  • settings.py 配置文件,如:遞歸的層數、併發數,延遲下載等
  • spiders      爬蟲目錄,如:建立文件,編寫爬蟲規則

注意:通常建立爬蟲文件時,以網站域名命名異步

二、編寫爬蟲scrapy

在spiders目錄中新建 xiaohuar_spider.py 文件

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import scrapy

class XiaoHuarSpider(scrapy.spiders.Spider):
    name = "nnnnn"  # 命名


    # allowed_domains = ["xiaohuar.com"]

    start_urls = [ # 起始url 內部是for循環
        "http://www.xiaohuar.com/hua/",
    ]
                    #response 裏面封裝着全部返回的數據
    def parse(self, response):  # 回調函數
        # print(response, type(response))
        # from scrapy.http.response.html import HtmlResponse
        # print(response.body_as_unicode())

        current_url = response.url # 當前請求的url
        body = response.body # 當前返回的內容
        unicode_body = response.body_as_unicode() # 編碼
        print body

三、運行

進入project_name目錄,運行命令

scrapy crawl spider_name --nolog

四、遞歸的訪問

以上的爬蟲僅僅是爬去初始頁,而咱們爬蟲是須要源源不斷的執行下去,直到全部的網頁被執行完畢

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import scrapy
from scrapy.http import Request
from scrapy.selector import HtmlXPathSelector
import re
import urllib
import os
 
 
class XiaoHuarSpider(scrapy.spiders.Spider):
    name = "xiaohuar"
    allowed_domains = ["xiaohuar.com"]
    start_urls = [
        "http://www.xiaohuar.com/list-1-1.html",
    ]
 
    def parse(self, response):
        # 分析頁面
        # 找到頁面中符合規則的內容(校花圖片),保存
        # 找到全部的a標籤,再訪問其餘a標籤,一層一層的搞下去
 
        hxs = HtmlXPathSelector(response)
 
        # 若是url是 http://www.xiaohuar.com/list-1-\d+.html
        if re.match('http://www.xiaohuar.com/list-1-\d+.html', response.url):
            items = hxs.select('//div[@class="item_list infinite_scroll"]/div')
            for i in range(len(items)):
                src = hxs.select('//div[@class="item_list infinite_scroll"]/div[%d]//div[@class="img"]/a/img/@src' % i).extract()
                name = hxs.select('//div[@class="item_list infinite_scroll"]/div[%d]//div[@class="img"]/span/text()' % i).extract()
                school = hxs.select('//div[@class="item_list infinite_scroll"]/div[%d]//div[@class="img"]/div[@class="btns"]/a/text()' % i).extract()
                if src:
                    ab_src = "http://www.xiaohuar.com" + src[0]
                    file_name = "%s_%s.jpg" % (school[0].encode('utf-8'), name[0].encode('utf-8'))
                    file_path = os.path.join("/Users/wupeiqi/PycharmProjects/beauty/pic", file_name)
                    urllib.urlretrieve(ab_src, file_path)
 
        # 獲取全部的url,繼續訪問,並在其中尋找相同的url
        all_urls = hxs.select('//a/@href').extract()
        for url in all_urls:
            if url.startswith('http://www.xiaohuar.com/list-1-'):
                yield Request(url, callback=self.parse)

以上代碼將符合規則的頁面中的圖片保存在指定目錄,而且在HTML源碼中找到全部的其餘 a 標籤的href屬性,從而「遞歸」的執行下去,直到全部的頁面都被訪問過爲止。以上代碼之因此能夠進行「遞歸」的訪問相關URL,關鍵在於parse方法使用了 yield Request對象。

注:能夠修改settings.py 中的配置文件,以此來指定「遞歸」的層數,如: DEPTH_LIMIT = 1  深度

 兩種定義查找的方式:

1, 即將過時的

 from scrapy.selector import HtmlXPathSelector
                hxs = HtmlXPathSelector(response)  # 即將過時了
                items = hxs.select('//div[@class="item_list infinite_scroll"]/div')

2,建議使用

from scrapy.selector import Selector # 推薦使用這一種
                ret = Selector(response=response).xpath('//div[@class="item_listinfinite_scroll"]/div')

3, 選擇器規則

selector:

        // 子子孫孫

        / 孩子

        //div[@class='c1'][@id='i1']  屬性選擇器

        //div//img/@src  獲取src屬性

         //div//a[1]  索引 第一個
        
        //div//a[1]//text()  內容
    
        ----- obj.extract() 真實的內容

        ===== 正則表達式
        
        //.select('div//a[1]').re('暱稱:(\w+)')

         <li class="item-"><a href="link.html">first item</a></li>
                 <li class="item-0"><a href="link1.html">first item</a></li>
                 <li class="item-1"><a href="link2.html">second item</a></li>

         '//li[re:test(@class, "item-\d*")]//@href'

問題實例: 

重複url 不訪問
        url加密 -》  集合set
            nid  加密值(索引) 原來的的值        
            new_url ==> 加密 

如何遞歸 
        DEPTH_LIMIT = 1 深度

        from scrapy.selector import Selector

            url_list = Selector(response=response).xpath('//a/#href')

            for url in url_list:  #  DEPTH_LIMIT = 1 深度

                    yield scrapy.Request(url=url,callback=self.parse)

內容格式化

 spider url規則    把本身的保存功能拆分到 pipelines  經過契約 items

1,yiled request() 交給下載器

#!/usr/bin/python
# -*- coding: UTF-8 -*-

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import scrapy
import urllib
import os
class XiaoHuarSpider(scrapy.spiders.Spider):
    name = "s2"  # 命名
    # allowed_domains = ["xiaohuar.com"]
    start_urls = [ # 起始url 內部是for循環
        "http://www.xiaohuar.com/hua/",
    ]
    def parse(self, response):  # 回調函數
        current_url = response.url # 當前請求的url
        body = response.body # 當前返回的內容
        unicode_body = response.body_as_unicode() # 編碼
        # 去body中獲取全部url
        from scrapy.selector import Selector
        url_list = Selector(response=response).xpath('//a/#href')
        for url in url_list:  #  DEPTH_LIMIT = 1 深度
            yield scrapy.Request(url=url,callback=self.parse)

2, yiled item()  交給 pipeline

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import scrapy
import urllib
import os
class XiaoHuarSpider(scrapy.spiders.Spider):
    name = "s2"  # 命名
    # allowed_domains = ["xiaohuar.com"]
    start_urls = [ # 起始url 內部是for循環
        "http://www.xiaohuar.com/hua/",
    ]
                    #response 裏面封裝着全部返回的數據
    def parse(self, response):  # 回調函數
        # print(response, type(response))
        # from scrapy.http.response.html import HtmlResponse
        # print(response.body_as_unicode())
        current_url = response.url # 當前請求的url
        from scrapy.selector import HtmlXPathSelector
        hxs = HtmlXPathSelector(response)  # 即將過時了
        items = hxs.select('//div[@class="item_list infinite_scroll"]/div')
        for i in range(len(items)):  # extract()  拿裏面真實的東西
            srcs = hxs.select('//div[@class="item_list infinite_scroll"]/div[%d]//div[@class="img"]/a/img/@src' % i).extract()
            names = hxs.select('//div[@class="item_list infinite_scroll"]/div[%d]//div[@class="img"]/span/text()' % i).extract()
            schools = hxs.select('//div[@class="item_list infinite_scroll"]/div[%d]//div[@class="img"]/div[@class="btns"]/a/text()' % i).extract()
            print names,srcs,schools
            if srcs and names and schools:
                print names[0],schools[0],srcs[0]
                try:
                    from spider1 import items
                    obj = items.Spider1Item()
                    obj['name'] = names[0]
                    obj['src'] = srcs[0]
                    obj['school'] = schools[0]
                    yield obj
                except Exception as e:
                    print e
# ret = [/uhdsjdnsd]
# print ret  uicod的表示
# print ret[0] 字符串
items 契約
# -*- coding: utf-8 -*-

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

import scrapy
class Spider1Item(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    name = scrapy.Field()
    src = scrapy.Field()
    school = scrapy.Field()
pipeline  保存
# -*- coding: utf-8 -*-

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

class Spider1Pipeline(object):
    def process_item(self, item, spider):
        ab_src = "http://www.xiaohuar.com" + item['src']  # 前綴
        file_name = item['name'].encode('utf-8') + '.jpg'
        import os
        import urllib
        file_path = os.path.join('D:\\',file_name)
        # file_name = "%s_%s.jpg" % (schools[0].encode('utf-8'), names[0].encode('utf-8'))
        # file_path = os.path.join("/Users/wupeiqi/PycharmProjects/beauty/pic", file_name)
        urllib.urlretrieve(ab_src, file_path) # 保存 地址和 路勁
        return item

生命流程圖
  

相關文章
相關標籤/搜索