scrapy學習-爬取天天基金網基金列表


描述

爬取http://fundact.eastmoney.com/banner/pg.html#ln網站的數據,
要求:爬取所有基金(有27頁)的基金代碼、基金名稱、單位凈值、日期、日增長率、近1周、近1月、近3月、近6月、近1年、近2年、近3年、今年來、成立來和手續費|起購金額。將爬取的數據放入mariaDB數據庫中。

環境描述

python 3.6.3
scrapy 1.4.0

步驟記錄

創建scrapy項目

進入打算放代碼的地方(F:\myPycharm_ws),創建項目funds,執行命令:

scrapy startproject funds

創建好項目后,查看會發現生成一些文件,這里對相關文件做下說明

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

接下來就可以使用pycharm打開項目進行開發了

設置在pycharm下運行scrapy項目

step 1:在funds項目里創建一個py文件(項目的任何地方都行)

from scrapy import cmdline

cmdline.execute("scrapy crawl fundsList".split())

step 2:配置 Run --> Edit Configurations (本人測試,不配置該步驟,也可運行)

運行方式:直接運行該.py文件即可。

分析如何獲取數據

由於通過ajax請求即可獲取到列表的全部結構化數據,所以我決定通過谷歌瀏覽器分析得到請求數據的url:
(參考:https://www.jianshu.com/p/1e35bcb1cf21)
通過分析,發現接口:https://fundapi.eastmoney.com/fundtradenew.aspx?ft=pg&sc=1n&st=desc&pi=1&pn=100&cp=&ct=&cd=&ms=&fr=&plevel=&fst=&ftype=&fr1=&fl=0&isab=


查看,接口返回的數據,發現並非直接是一個json,而是形如這樣的:我們只需取出datas項就行

OK,那我直接請求獲取這個接口的數據即可。

編寫代碼

step 1:設置item

class FundsItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()

    code = scrapy.Field()   # 基金代碼
    name = scrapy.Field()   # 基金名稱
    unitNetWorth = scrapy.Field()   # 單位凈值
    day = scrapy.Field()    # 日期
    dayOfGrowth = scrapy.Field()  # 日增長率
    recent1Week = scrapy.Field()    # 最近一周
    recent1Month = scrapy.Field()   # 最近一月
    recent3Month = scrapy.Field()   # 最近三月
    recent6Month = scrapy.Field()   # 最近六月
    recent1Year = scrapy.Field()    # 最近一年
    recent2Year = scrapy.Field()    # 最近二年
    recent3Year = scrapy.Field()    # 最近三年
    fromThisYear = scrapy.Field()   # 今年以來
    fromBuild = scrapy.Field()  # 成立以來
    serviceCharge = scrapy.Field()  # 手續費
    upEnoughAmount = scrapy.Field()     # 起夠金額

    pass

step 2:編寫spider

import scrapy
import json

from scrapy.http import Request
from funds.items import FundsItem

class FundsSpider(scrapy.Spider):
    name = 'fundsList'   # 唯一,用於區別Spider。運行爬蟲時,就要使用該名字
    allowed_domains = ['fund.eastmoney.com']  # 允許訪問的域

    # 初始url。在爬取從start_urls自動開始后,服務器返回的響應會自動傳遞給parse(self, response)方法。
    # 說明:該url可直接獲取到所有基金的相關數據
    # start_url = ['http://fundact.eastmoney.com/banner/pg.html#ln']

    # custome_setting可用於自定義每個spider的設置,而setting.py中的都是全局屬性的,當你的scrapy工程里有多個spider的時候這個custom_setting就顯得很有用了
    # custome_setting = {
    #
    # }

    # spider中初始的request是通過調用 start_requests() 來獲取的。 start_requests() 讀取 start_urls 中的URL, 並以 parse 為回調函數生成 Request 。
    # 重寫start_requests也就不會從start_urls generate Requests了
    def start_requests(self):
        url = 'https://fundapi.eastmoney.com/fundtradenew.aspx?ft=pg&sc=1n&st=desc&pi=1&pn=3000&cp=&ct=&cd=&ms=&fr=&plevel=&fst=&ftype=&fr1=&fl=0&isab='
        requests = []
        request = scrapy.Request(url,callback=self.parse_funds_list)
        requests.append(request)
        return requests

    def parse_funds_list(self,response):
        datas = response.body.decode('UTF-8')

        # 取出json部門
        datas = datas[datas.find('{'):datas.find('}')+1] # 從出現第一個{開始,取到}

        # 給json各字段名添加雙引號
        datas = datas.replace('datas', '\"datas\"')
        datas = datas.replace('allRecords', '\"allRecords\"')
        datas = datas.replace('pageIndex', '\"pageIndex\"')
        datas = datas.replace('pageNum', '\"pageNum\"')
        datas = datas.replace('allPages', '\"allPages\"')

        jsonBody = json.loads(datas)
        jsonDatas = jsonBody['datas']

        fundsItems = []
        for data in jsonDatas:
            fundsItem = FundsItem()
            fundsArray = data.split('|')
            fundsItem['code'] = fundsArray[0]
            fundsItem['name'] = fundsArray[1]
            fundsItem['day'] = fundsArray[3]
            fundsItem['unitNetWorth'] = fundsArray[4]
            fundsItem['dayOfGrowth'] = fundsArray[5]
            fundsItem['recent1Week'] = fundsArray[6]
            fundsItem['recent1Month'] = fundsArray[7]
            fundsItem['recent3Month'] = fundsArray[8]
            fundsItem['recent6Month'] = fundsArray[9]
            fundsItem['recent1Year'] = fundsArray[10]
            fundsItem['recent2Year'] = fundsArray[11]
            fundsItem['recent3Year'] = fundsArray[12]
            fundsItem['fromThisYear'] = fundsArray[13]
            fundsItem['fromBuild'] = fundsArray[14]
            fundsItem['serviceCharge'] = fundsArray[18]
            fundsItem['upEnoughAmount'] = fundsArray[24]
            fundsItems.append(fundsItem)
        return fundsItems

step 3:配置settings.py

custome_setting可用於自定義每個spider的設置,而setting.py中的都是全局屬性的,當你的scrapy工程里有多個spider的時候這個custom_setting就顯得很有用了。
但是我目前項目暫時只有一個爬蟲,所以暫時使用setting.py設置spider。

設置了DEFAULT_REQUEST_HEADERS(本次爬蟲由於是請求接口,該項不配置也可)

DEFAULT_REQUEST_HEADERS = {
  # 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  # 'Accept-Language': 'en',
    'Accept':'*/*',
    'Accept-Encoding':'gzip, deflate, br',
    'Accept-Language':'zh-CN,zh;q=0.9',
    'Connection':'keep-alive',
    'Cookie':'st_pvi=72856792768813; UM_distinctid=1604442b00777b-07f0a512f81594-5e183017-100200-1604442b008b52; qgqp_b_id=f10107e9d27d5fe2099a361a52fcb296; st_si=08923516920112; ASP.NET_SessionId=s3mypeza3w34uq2zsnxl5azj',
    'Host':'fundapi.eastmoney.com',
    'Referer':'http://fundact.eastmoney.com/banner/pg.html',
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
}

設置ITEM_PIPELINES

ITEM_PIPELINES = {
   'funds.pipelines.FundsPipeline': 300,
}

pipelines.py,將數據寫入我本地數據庫里

import pymysql.cursors

class FundsPipeline(object):
    def process_item(self, item, spider):
        # 連接數據庫
        connection = pymysql.connect(host='localhost',
                                     user='root',
                                     password='123',
                                     db='test',
                                     charset='utf8mb4',
                                     cursorclass=pymysql.cursors.DictCursor)

        sql = "INSERT INTO funds(code,name,unitNetWorth,day,dayOfGrowth,recent1Week,recent1Month,recent3Month,recent6Month,recent1Year,recent2Year,recent3Year,fromThisYear,fromBuild,serviceCharge,upEnoughAmount)\
                                      VALUES('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')" % (
            item['code'], item['name'], item['unitNetWorth'], item['day'], item['dayOfGrowth'], item['recent1Week'], \
            item['recent1Month'], item['recent3Month'], item['recent6Month'], item['recent1Year'], item['recent2Year'],
            item['recent3Year'], item['fromThisYear'], item['fromBuild'], item['serviceCharge'], item['upEnoughAmount'])

        with connection.cursor() as cursor:
            cursor.execute(sql) # 執行sql

        connection.commit()  # 提交到數據庫執行
        connection.close()

        return item

錯誤處理

ModuleNotFoundError: No module named 'pymysql'

解決辦法:(參考:https://stackoverflow.com/questions/33446347/no-module-named-pymysql)

pip install PyMySQL

1366, "Incorrect string value: '\xE6\x99\xAF\xE9\xA1\xBA...' for column 'name' at row 1"

即:入庫的中文是亂碼

查看數據庫編碼,為latin1。
解決辦法:

alter table funds convert to character set utf8


免責聲明!

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



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