python3.8 安裝scrapy及其使用 ,爬取糗事百科小案例


yls 2020/5/27

安裝scrapy之前,先安裝 twisted,否則會報錯

  1. https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted 中下載與python對應版本的 Twisted
    ,cp38對應py3.8,自行選擇32 or 64位。
  2. 找到下載好后的Twisted文件地址,在cmd運行命令 pip install 文件位置
    例如:pip install C:\Users\name\Downloads\Twisted-18.7.0-cp37-cp37m-win_amd64.whl
    若安裝時報錯如下:
    D:\python>pip3 install Twisted-20.3.0-cp38-cp38-win_amd64.whl
    ERROR: Twisted-20.3.0-cp38-cp38-win_amd64.whl is not a supported wheel on this platform.
    則 修改文件名為 Twisted-20.3.0-cp38-cp38-win32.whl 后,重新安裝

安裝 scrapy

# pip默認國外的源文件 http://mirrors.aliyun.com/pypi/simple/ 使用國內源
1. pip3 --default-timeout=100 install Scrapy -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

創建項目實例

scrapy startproject [項目的名字]

例如:scrapy startproject tencent

創建爬蟲

進入項目根目錄 cd tencent
創建爬蟲  scrapy genspider [爬蟲的名字] [爬蟲的域名]
例如:scrapy genspider example example.com
注意:爬蟲的名字不能和項目的名字相同

運行一個爬蟲

1. 直接在命令行運行
scrapy crawl [爬蟲名]
2. 寫一個py腳本,直接運行腳本即可(這種方式,可以在程序中使用斷點測試)
from scrapy import cmdline

cmdline.execute(["scrapy", "crawl", "爬蟲名"])

運行爬蟲前,一般需要在 settings.py 中設置 USER_AGENT 和 Obey robots.txt rules

USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36'

ROBOTSTXT_OBEY = False

使用日志

import logging

logger=logging.getLogger(__name__)  #可以使日志打印時,顯示當前所在文件名

logger.warning(item)  #示例

爬蟲中打印日志的方式,在settings.py中設置日志級別和日志文件

LOG_LEVEL="WARNING"
LOG_FILE="./log.log" #日志保存文件,設置以后,終端不會顯示日志記錄

在settings.py中開啟管道

ITEM_PIPELINES = {
   'tutorial.pipelines.TutorialPipeline': 300,    #300表示優先級,數字越小越優先

   'tutorial.pipelines.TutorialPipeline1': 301,  # 300表示優先級,數字越小越優先

}

scrapy案例一

爬取糗事百科網站中的段子
數據包括:作者,段子內容,發布的時間
根據上面的介紹創建爬蟲即可

1. 定義 items.py

import scrapy

"""
定義要爬取的數據字段,就可以不使用字典了
"""


class QsbkItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapylearn.Field()
    author = scrapy.Field()
    content = scrapy.Field()
    time = scrapy.Field()

2. 在settings.py中添加配置

USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False
# 激活通道
ITEM_PIPELINES = {
   'qsbk.pipelines.QsbkPipeline': 300,
}

3. 編輯 piplines.py ,保存爬取數據結果到json文件中,有三種方式

"""
若要激活 pipline ,需要在settings.py中設置 ITEM_PIPELINES
示例如下:
ITEM_PIPELINES = {
   'qsbk.pipelines.QsbkPipeline': 300,
}
"""

"""
將數據保存到json文件中,方式一 
使用 json
"""
# import json
#
#
# class QsbkPipeline:
#     # 當爬蟲被打開的時候會調用
#     def open_spider(self, spider):
#         print("爬蟲開始執行。。。")
#
#     # 當爬蟲有item傳過來的時候會調用
#     def process_item(self, item, spider):
#         """
#          對item進行處理操作,例如保存到json文件:
#          with open(filename, 'a',encoding='utf-8') as f:
#             line = json.dumps(dict(item), ensure_ascii=False) + '\n'
#             f.write(line)
#         """
#         fileName = "duanzi.json"
#         # 將item轉換為json格式
#         duanzi = json.dumps(dict(item), ensure_ascii=False)
#         with open(fileName, 'a', encoding='utf-8') as f:
#             f.write(duanzi + "\n")
#         return item
#
#     # 當爬蟲關閉的時候會調用
#     def close_spider(self, spider):
#         print("爬蟲執行結束")
"""
將數據保存到json文件中,方式二
使用 JsonItemExporter,保存結果是滿足json格式的列表
缺點是數據量如果太大,會占用內存,因為爬蟲執行完之前數據都保存在內存中,最后統一寫入到磁盤
"""
# from scrapy.exporters import JsonItemExporter
#
#
# class QsbkPipeline:
#     # 當爬蟲被打開的時候會調用
#     def open_spider(self, spider):
#         print("爬蟲開始執行。。。")
#         fileName = "duanzi2.json"
#         self.fp = open(fileName, "wb")  # 必須以二進制的形式打開文件
#         self.exporter = JsonItemExporter(self.fp, ensure_ascii=False, encoding="utf-8")
#         self.exporter.start_exporting()
#
#     # 當爬蟲有item傳過來的時候會調用
#     def process_item(self, item, spider):
#         self.exporter.export_item(item)
#         return item
#
#     # 當爬蟲關閉的時候會調用
#     def close_spider(self, spider):
#         self.exporter.finish_exporting()
#         print("爬蟲執行結束")
"""
將數據保存到json文件中,方式三
使用 JsonLinesItemExporter,一行一行的添加,和 方式一效果 一樣
"""
from scrapy.exporters import JsonLinesItemExporter


class QsbkPipeline:
    # 當爬蟲被打開的時候會調用
    def open_spider(self, spider):
        print("爬蟲開始執行。。。")
        fileName = "duanzi3.json"
        self.fp = open(fileName, "wb")  # 必須以二進制的形式打開文件
        self.exporter = JsonLinesItemExporter(self.fp, ensure_ascii=False, encoding="utf-8")

    # 當爬蟲有item傳過來的時候會調用
    def process_item(self, item, spider):
        self.exporter.export_item(item)
        return item

    # 當爬蟲關閉的時候會調用
    def close_spider(self, spider):
        print("爬蟲執行結束")

4. 編輯爬蟲邏輯

# -*- coding: utf-8 -*-
from copy import deepcopy
import scrapy
from scrapy.http.response.html import HtmlResponse
from scrapylearn.qsbk.qsbk.items import QsbkItem


class QsbkspiderSpider(scrapy.Spider):
    # 爬蟲的名稱
    name = 'qsbkSpider'
    # 爬蟲允許的域名,限制爬蟲的范圍,不屬於該域名的網址,就不會去爬取
    allowed_domains = ['qiushibaike.com']
    # 開始爬蟲的網址
    start_urls = ['https://www.qiushibaike.com/text/page/1/']
    # 自定義變量,為爬取多頁面提供url的前一部分
    base_domain = "https://www.qiushibaike.com"

    def parse(self, response):
        # print("=" * 40)
        # # 打印出response的類型
        # print(type(response))
        # print("=" * 40)
        duanzidivs = response.xpath("//div[@class='col1 old-style-col1']/div")
        for duanzi in duanzidivs:
            author = duanzi.xpath(".//h2/text()").extract_first().strip()  # extract = getall ,extract_first = get
            content = duanzi.xpath(".//div[@class='content']/span/text()").getall()
            # 使用items代替字典
            # item = {"author": author, "content": content}
            item = QsbkItem(author=author, content=content)
            infoUrl = self.base_domain + duanzi.xpath("./a[1]/@href").get()
            # 可以將已經解析好的數據傳遞到下一個解析,使用深拷貝,否則下一個for循環中的值會改變上一個item的值
            yield scrapy.Request(infoUrl, callback=self.parseTime, meta={"item": deepcopy(item)})

        # 下一頁標簽中的 url
        nextUrl = self.base_domain + response.xpath("//ul[@class='pagination']/li[last()]/a/@href").get()
        if not nextUrl:
            return
        else:
            yield scrapy.Request(nextUrl, callback=self.parse)

    # 在段子的全部信息頁面解析該段子發布的時間
    def parseTime(self, response):
        # 接收上一個解析函數傳遞的數據
        item = response.meta["item"]
        time = response.xpath("//span[@class='stats-time']/text()").get().strip()
        item["time"] = time
        # yield 是將item一個一個的返回,也可以將item 存儲到一個列表[]中,最后使用return 全部返回
        yield item

5. 代碼托管地址:https://github.com/1612480331/scrapy/tree/master/qsbk


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM