Spider_scrapy

多線程爬蟲

進程線程回顧

  • 進程
    • 系統中正在運行的一個應用程序
    • 1個CPU核心1次只能執行1個進程,其餘進程處於非運行狀態
    • N個CPU核心可同時執行N個任務
  • 線程
    • 進程中包含的執行單元,1個進程可包含多個線程
    • 線程可以使用所屬進程空間(1次只能執行1個線程,阻塞)
    • 鎖:防止多個線程同時使用共享空間
  • GIL:全局解釋鎖
    • 執行通行證,僅此1個,拿到了通行證可執行,不然等
  • 應用場景
    • 多進程:大量的密集的計算
    • 多線程:I/O密集
      • 爬蟲:網絡I/O
    • 寫文件:本次磁盤I/O

案例:使用多線程爬取 百思不得其姐 段子

  • 爬取目標 :段子內容
  • URL :http://www.budejie.com/
  • xpath表達式
    • //div[@class="j-r-list-c-desc"]/a/text()
  • 知識點
    • 隊列(from queue import Queue)
      • put()
      • get()
      • Queue.empty():是否爲空
      • Queue.join():若是隊列爲空,執行其餘程序
    • 線程(import threading)
      • threading.Thread(target=...)
import requests
from lxml import etree
from queue import Queue
import threading
import time


class BsSpider:
    def __init__(self):
        self.baseurl = "http://www.budejie.com/"
        self.headers = {"User_Agent": "Mozilla/5.0"}
        self.urlQueue = Queue()  # url隊列
        self.resQueue = Queue()  # 響應隊列

    # 生成URL隊列
    def get_url(self):
        for num in range(1, 51):
            url = self.baseurl + str(num)  # 1是第一頁
            self.urlQueue.put(url)

    # 響應隊列
    def get_html(self):
        while True:
            url = self.urlQueue.get()
            res = requests.get(url, headers=self.headers)
            res.encoding = 'utf-8'
            html = res.text
            # 放到響應隊列
            self.resQueue.put(html)
            # 清除此任務
            self.urlQueue.task_done()

    # 解析頁面
    def get_content(self):
        while True:
            # 從響應隊列中一次獲取html源碼
            html = self.resQueue.get()
            parse_html = etree.HTML(html)
            r_list = parse_html.xpath('//div[@class="j-r-list-c-desc"]/a/text()')
            for r in r_list:
                print(r + "\n")
            # 清除任務
            self.resQueue.task_done()

    def main(self):
        # 存放全部的線程
        thread_list = []
        # 獲取url隊列
        self.get_url()
        # 建立getpage線程
        for i in range(3):
            thread_res = threading.Thread(target=self.get_html)
            thread_list.append(thread_res)
        for i in range(2):
            thread_parse = threading.Thread(target=self.get_content)
            thread_list.append(thread_parse)
        # 全部線程開始幹活
        for th in thread_list:
            th.setDaemon(True)
            th.start()
        # 若是隊列爲空,則執行其餘程序
        self.urlQueue.join()
        self.resQueue.join()
        print("運行結束")


if __name__ == '__main__':
    begin = time.time()
    spider = BsSpider()
    spider.main()
    end = time.time()
    print("運行時間:", end - begin)

BeautifulSoup

  • 定義
    • HTML或XML的解析器,依賴於lxml
  • 安裝:python -m pip install beautifulsoup4
  • 導模塊:from bs4 import BeautifulSoup
  • 使用流程
    • 導入模塊
      • from bs4 import BeautifulSoup
    • 建立解析對象
      • soup = BeautifulSoup(html,'lxml')
    • 查找節點對象
      • soup.find_all(name="屬性值")

支持的解析庫

  • lxml:BeautifulSoup(html,'lxml')
    • 速度快,文檔容錯能力強
  • python標準庫:BeautifulSoup(html,'html.parser')
    • 速度通常
  • xml解析器:BeautifulSoup(html,'xml')
    • 速度快,文檔容錯能力強

節點選擇器

  • 選擇節點
    • soup.節點名soup.a、soup.ul
  • 獲取文本內容
    • soup.節點名.string
  • 經常使用方法:find_all():返回列表
    • r_list = soup.find_all(屬性名="屬性值")
      • r_list = soup.find_all(class="test") # 報錯嘗試使用class_
    • r_list=soup.find_all("節點名",attrs={"名":"值"})
      • r_list=soup.find_all("div",attrs={"class":"test"}
from bs4 import BeautifulSoup

html = '<div id="text">哈哈</div>'

# 建立解析對象
soup = BeautifulSoup(html, 'lxml')
# 查找節點
r_list = soup.find_all(id="text")
print(r_list)
for r in r_list:
    print(r.get_text())

r_list = soup.find_all("div", attrs={'id': "text"})
print(r_list)

####################################
html = '''<div class="test">你好</div>
<div class="test">再見</div>
<div class="test2">
    <span>第二次</span>
</div>'''

# class爲test的div的文本內容
soup = BeautifulSoup(html, 'lxml')
divs = soup.find_all("div", attrs={"class": "test"})
print(type(divs))
for div in divs:
    print(div.string)
    print(div.get_text())

# class爲test2的div下的span中的文本內容
divs = soup.find_all("div", attrs={"class": "test2"})
for div in divs:
    print(div.span.string)

Scrapy框架

解釋

  • 異步處理框架,可配置和可擴展程度很是高,Python中使用最普遍的爬蟲框架

框架組成

  • 引擎(Engine) :整個框架核心
  • 調度器(Scheduler) :接受從引擎發過來的URL,入隊列
  • 下載器(Downloader):下載網頁源碼,返回給爬蟲程序
  • 項目管道(Item Pipeline) :數據處理
  • 下載器中間件(Downloader Middlewares)
    • 處理引擎與下載器之間的請求與響應
  • 蜘蛛中間件(Spider Middlerwares)
    • 處理爬蟲程序輸入響應和輸出結果以及新的請求
  • Item:定義爬取結果的數據結構,爬取的數據會被賦值爲Item對象

運行流程

  1. Engine開始統攬全局,向Spider索要URL
  2. Engine拿到url後,給Scheduler入隊列
  3. Schduler從隊列中拿出url給Engine,經過Downloader Middlewares給Downloader去下載
  4. Downloader下載完成,把response給Engine
  5. Engine把response經過Spider Middlewares給Spider
  6. Spider處理完成後,
    • 把數據給Engine,交給Item Pipeline處理,
    • 把新的URL給Engine,重複2-6步
  7. Scheduler中沒有任何Requests請求後,程序結束

Scrapy爬蟲項目步驟

  1. 新建項目
    • scrapy startproject 項目名
  2. 明確目標(items.py)
  3. 製做爬蟲程序
    • cd XXX/spiders:scrapy genspider 文件名 域名
  4. 處理數據(pipelines.py)
  5. 配置settings.py
  6. 運行爬蟲項目
    • scrapy crawl 爬蟲名

scrapy項目文件詳解

  • 目錄結構
    testspider/
    ├── scrapy.cfg #項目基本配置文件,不用改
    └── testspider
    ├── init.py
    ├── items.py # 定義爬取數據的結構
    ├── middlewares.py # 下載器中間件和蜘蛛中間件實現
    ├── pipelines.py # 處理數據
    ├── settings.py # 項目全局配置
    └── spiders # 存放爬蟲程序
    ├── init.py
    ├── myspider.py

settings.py配置

# 是否遵照robots協議,該爲False
  ROBOTSTXT_OBEY = False

  # 最大併發量,默認爲16個
  CONCURRENT_REQUESTS = 32

  # 下載延遲時間爲3秒
  DOWNLOAD_DELAY = 3

  # 請求報頭
  DEFAULT_REQUEST_HEADERS = {
    'User-Agent': "Mozilla/5.0",
     'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
     'Accept-Language': 'en',
    }

  # 蜘蛛中間件
  SPIDER_MIDDLEWARES = {
     'testspider.middlewares.TestspiderSpiderMiddleware': 543,
    }

  # 下載器中間件
  DOWNLOADER_MIDDLEWARES = {
     'testspider.middlewares.TestspiderDownloaderMiddleware': 543,
    }

  # 管道文件
  ITEM_PIPELINES = {
     'testspider.pipelines.TestspiderPipeline': 300,
    }

案例:抓取百度首頁源碼,存到baidu.html中

  1. scrapy startproject baidu
  2. cd baidu/baidu
  3. subl items.py(此示例可不用操做)
  4. cd spiders
  5. scrapy genspider baiduspider baidu.com
    #爬蟲名
    #域名
    #start_urls
    def parse(self,response):
    with open("baidu.html","w") as f:
    f.write(response.text)
  6. subl settings.py
    • 關閉robots協議
    • 添加Headers
  7. cd spiders
  8. scrapy crawl baiduspider

pycharm運行scrapy項目

  1. 建立文件begin.py和scrapy.cfg同目錄
    from scrapy import cmdline
    cmdline.execute("scrapy crawl baiduspider".split())
  2. Editconfigurations -> + -> python
    name : spider
    Script : begin.py的路徑
    working directory : 你本身的項目路徑
  3. 點擊運行

生成器

  1. yield做用 :把一個函數當作一個生成器使用
  2. 斐波那契數列 Fib.py
  3. yield特色 :讓函數暫停,等待下1次調用
# Fib.py
def fib(n):
    a, b, s = 0, 1, 0
    while s < n:
        a, b = b, a + b
        s += 1
        yield b

print(fib(5).__next__())
for i in fib(10):
    print(i)
1
1
2
3
5
8
13
21
34
55
89

項目:csdn

  1. 知識點 yield 、pipelines.py
  2. 目標
    • https://blog.csdn.net/qq_42231391/article/details/83506181
    • 標題、發表時間、閱讀數
    • 步驟
      • 建立項目
      • 定義數據結構(items.py)
      • 建立爬蟲程序
      • 第3步抓取的數據經過項目管道去處理
      • 全局配置
      • 運行爬蟲程序

項目:Daomu

  1. URL :http://www.daomubiji.com/dao-mu-bi-ji-1
  2. 目標
    • 書名、書的標題、章節名稱、章節數量、章節連接
  3. 步驟
    • 建立項目 Daomu
    • 改items.py(定義數據結構)
    • 建立爬蟲文件
    • 改pipelines.py(項目管道文件)
    • 配置settings.py
    • 運行爬蟲

知識點

  • extract():獲取選擇器對象中的文本內容
    • response.xpath('.../text()') 獲得選擇器對象(節點文本) [<selector ...,data='文本內容'>]
    • extract() 把選擇器對象中的文本取出來 ['文本內容']
  • 爬蟲程序中的 start_urls必須爲列表
    • start_urls = []
  • pipelines.py中必須有1個函數叫
    • process_item(self,item,spider),固然還能夠寫任何其餘函數

存入MongoDB數據庫

  • 在settings.py中定義相關變量
    • MONGODB_HOST =
    • MONGODB_PORT =
  • 可在pipelines.py中新建一個class
    from Daomu import settings
    class DaomumongoPipeline(object):
    def init(self):
    host = settings.MONGODB_HOST
  • 在settings.py文件中設置你的項目管道
    ITEM_PIPELINES = {
    "Daomu.pipelines.DaomumongoPipeline":100,
    }html

    存入MySQL數據庫

  • self.db.commit()
  • Csdn項目存到mongodb和mysqlpython

騰訊招聘網站案例

  • URL
    • 第1頁:https://careers.tencent.com/search.html?index=1
    • 第2頁:https://careers.tencent.com/search.html?index=2
  • Xpath匹配
    • 基準xpath表達式(每一個職位節點對象)
    • //div[@class="search-content"]
      • 職位名稱:.//h4/text()
      • 工做地點:.//span[2]/text()
      • 職位類別:.//span[3]/text()
      • 發佈時間:.//span[4]/text()
      • 詳情信息:.//p[2]/text()

設置手機抓包

- Fiddler(設置抓包)
- 在手機上安裝證書
    - 手機瀏覽器打開:http://IP地址:8888 (IP地址是你電腦的IP,8888是Fiddler設置的端口)
    - 在頁面上下載(FiddlerRoot certificate)
    - 下載文件名:FiddlerRoot.cer
    0 直接安裝
- 設置代理
    - 打開手機上已鏈接的無線, 代理設置 -> 改爲 手動
    - IP地址:你電腦的IP (ipconfig / ifconfig)
    - 端口號:8888

如何設置隨機User-Agent

  1. settings.py(少許User-Agent切換,不推薦)
    • 定義USER_AGENT變量值
    • DEFAULT_REQUEST_HEADER={"User-Agent":"",}
  2. 設置中間件的方法來實現
    • 項目目錄中新建user_agents.py,放大量Agent
    • user_agents = ['','','','','']
    • middlewares.py寫類:
      from 項目名.user_agents import user_agents
      import random
      class RandomUserAgentMiddleware(object):
      def process_request(self,request,spider):
      request.headers["User-Agent"] = random.choice(user_agents)
    • 設置settings.py
      DOWNLOADER_MIDDLEWARES = {"項目名.middlewares.RandomUserAgentMiddleware" : 1}
  3. 直接在middlewares.py中添加類
    class RandomUserAgentMiddleware(object):
    def init(self):
    self.user_agents = ['','','','','','']
    def process_request(self,request,spider):
    request.header['User-Agent'] = random.choice(self.user_agents)

設置代理(DOWNLOADER MIDDLEWARES)

  • middlewares.py中添加代理中間件ProxyMiddleware
    class ProxyMiddleware(object):
    def process_request(self,request,spider):
    request.meta['proxy'] = "http://180.167.162.166:8080"
  • settings.py中添加
    DOWNLOADER_MIDDLEWARES = {
    'Tengxun.middlewares.RandomUserAgentMiddleware': 543,
    'Tengxun.middlewares.ProxyMiddleware' : 250,
    }

圖片管道 :ImagePipeline

  • 使用流程(要操做的文件)
    1. settings.py
      • 設置圖片要保存的路徑的變量
      • IMAGES_STORE = "/home/tarena/aaa/aaa/images"
    2. pipelines.py
      • 導入scrapy定義好的圖片管道類
      • from scrapy.pipelines.images import ImagesPipeline
    3. 定義本身的class,繼承scrapy的圖片管道類
      class AAAImagePipeline(ImagesPipeline):
      def get_media_requests(self,item,info):
      ... ...

案例 :鬥魚圖片抓取案例(手機app)

  • 菜單 --> 顏值
    • http://capi.douyucdn.cn/api/v1/getVerticalRoom?limit=20&offset=0
  • 抓取目標
    • 圖片連接
    • 主播名
    • 城市
    • 把全部圖片保存在 IMAGES_STORE
  • 步驟
    1. 前提 :手機和電腦一個局域網
    2. Fiddler抓包工具
      Connections : Allow remote computers to ..
      HTTPS : ...from all processes
    3. IP地址 :Win+r -> cmd -> ipconfig
    4. 配置手機
      • 手機瀏覽器 :http://IP:8888
      • 下載 FiddlerRoot certificate
    5. 安裝
      • 設置 -> 更多 -> ... -> 從存儲設備安裝
    6. 設置手機代理
      • 長按 wifi,->代理
      • IP地址 :
      • 端口號 :

dont_filter參數mysql

scrapy.Request(url,callback=...,dont_filter=False)
  dont_filter參數 :False->自動對URL進行去重
                    True -> 不會對URL進行去重

scrapy對接selenium+phantomjs

  1. 建立項目 :Jd
  2. middlewares.py中添加selenium
    • 導模塊 :from selenium import webdriver
    • 定義中間件
      class seleniumMiddleware(object):
      ...
      def process_request(self,request,info):
      # 注意:參數爲request的url
      self.driver.get(request.url)
  3. settings.py
    • DOWNLOADER_MIDDLEWARES={"Jd.middleware.seleniumMiddleware":20}

Scrapy模擬登錄

  • 建立項目 :cnblog
  • 建立爬蟲文件

機器視覺與tesseract

  • OCR(Optical Character Recognition)光學字符識別
    • 掃描字符 :經過字符形狀 --> 電子文本,OCR有不少的底層識別庫
  • tesseract(谷歌維護的OCR識別開源庫,不能import,工具)
    1. 安裝
      • windows下載安裝包
        • https://sourceforge.net/projects/tesseract-ocr-alt/files/tesseract-ocr-setup-3.02.02.exe/download
        • 安裝完成後添加到環境變量
      • Ubuntu : suo apt-get install tesseract-ocr
      • Mac : brew install tesseract
    2. 驗證
      • 終端 :tesseract test1.jpg text1.txt
    3. 安裝pytesseract模塊
      • python -m pip install pytesseract
      • 方法不多,就用1個,圖片轉字符串:image_to_sting
  • Python圖片的標準庫
    • from PIL import Image

示例

  1. 驗證碼圖片以wb方式寫入到本地
  2. image = Image.open("驗證碼.jpg")
  3. s = pytesseract.image_to_string(image)

分佈式介紹

  • 條件
    1. 多臺服務器(數據中心、雲服務器)
    2. 網絡帶寬
  • 分佈式爬蟲方式
    1. 主從分佈式
      • 主機分配子機的目標url
    2. 對等分佈式
  • scrapy-redis
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息