Сканирование данных онлайн-кредита и анализ данных

Python рептилия анализ данных искусственный интеллект

Об источниках данных

Проект был написан в начале июля 2017 года, в основном с использованием Python, сканирующего чистую ипотечную ссуду, а также все данные для анализа. Чистая ссуда дома является крупнейшей платформой данных P2P для всех двадцати крупнейших кредитных платформ Китая P2P.Адрес источника

парсинг данных

Анализ захвата пакетов

Инструмент захвата пакетов в основном использует сетевой столбец инструмента разработчика Chrome.Все данные Net Loan Home представляют собой данные json, возвращаемые ajax, в то время как Renrendai имеет как возвращаемые данные ajax, так и html-страницу для прямого генерирования данных.

экземпляр запроса

QQ截图20180123205633.png
Из данных можно увидеть способ запроса данных (GET или POST), заголовки запроса и параметры запроса.
QQ截图20180123205843.png
Из данных запроса вы можете увидеть формат возвращаемых данных (в этом примере json), структуру данных и конкретные данные. Примечание. Это интерфейс серверной части запроса API Net Loan Home. Когда сканер был написан, интерфейс данных отличался от текущего интерфейса запроса, поэтому часть сканера данных Net Loan Home недействительна.

Запрос на строительство

Сформировать запрос на основе результатов анализа перехвата пакетов. В этом проекте используйте библиотеку запросов Python для имитации http-запросов. Конкретный код:

import requests
class SessionUtil():
    def __init__(self,headers=None,cookie=None):
        self.session=requests.Session()
        if headers is None:
            headersStr={"Accept":"application/json, text/javascript, */*; q=0.01",
                "X-Requested-With":"XMLHttpRequest",
                "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
                "Accept-Encoding":"gzip, deflate, sdch, br",
                "Accept-Language":"zh-CN,zh;q=0.8"
                }
            self.headers=headersStr
        else:
            self.headers=headers
        self.cookie=cookie
    //发送get请求
    def getReq(self,url):
        return self.session.get(url,headers=self.headers).text
    def addCookie(self,cookie):
        self.headers['cookie']=cookie
    //发送post请求
    def postReq(self,url,param):
        return self.session.post(url, param).text

При настройке заголовка запроса в поле ключа устанавливается только «User-Agent», а для Wangdaijia и Renrendai мер против сканирования нет, и даже поле «Referer» не нужно устанавливать для предотвращения междоменного ошибки.

Экземпляр сканера

Ниже приведен пример обходчика

import json
import time
from databaseUtil import DatabaseUtil
from sessionUtil import SessionUtil
from dictUtil import DictUtil
from logUtil import LogUtil
import traceback
def handleData(returnStr):
    jsonData=json.loads(returnStr)
    platData=jsonData.get('data').get('platOuterVo')
    return platData
def storeData(jsonOne,conn,cur,platId):
    actualCapital=jsonOne.get('actualCapital')
    aliasName=jsonOne.get('aliasName')
    association=jsonOne.get('association')
    associationDetail=jsonOne.get('associationDetail')
    autoBid=jsonOne.get('autoBid')
    autoBidCode=jsonOne.get('autoBidCode')
    bankCapital=jsonOne.get('bankCapital')
    bankFunds=jsonOne.get('bankFunds')
    bidSecurity=jsonOne.get('bidSecurity')
    bindingFlag=jsonOne.get('bindingFlag')
    businessType=jsonOne.get('businessType')
    companyName=jsonOne.get('companyName')
    credit=jsonOne.get('credit')
    creditLevel=jsonOne.get('creditLevel')
    delayScore=jsonOne.get('delayScore')
    delayScoreDetail=jsonOne.get('delayScoreDetail')
    displayFlg=jsonOne.get('displayFlg')
    drawScore=jsonOne.get('drawScore')
    drawScoreDetail=jsonOne.get('drawScoreDetail')
    equityVoList=jsonOne.get('equityVoList')
    experienceScore=jsonOne.get('experienceScore')
    experienceScoreDetail=jsonOne.get('experienceScoreDetail')
    fundCapital=jsonOne.get('fundCapital')
    gjlhhFlag=jsonOne.get('gjlhhFlag')
    gjlhhTime=jsonOne.get('gjlhhTime')
    gruarantee=jsonOne.get('gruarantee')
    inspection=jsonOne.get('inspection')
    juridicalPerson=jsonOne.get('juridicalPerson')
    locationArea=jsonOne.get('locationArea')
    locationAreaName=jsonOne.get('locationAreaName')
    locationCity=jsonOne.get('locationCity')
    locationCityName=jsonOne.get('locationCityName')
    manageExpense=jsonOne.get('manageExpense')
    manageExpenseDetail=jsonOne.get('manageExpenseDetail')
    newTrustCreditor=jsonOne.get('newTrustCreditor')
    newTrustCreditorCode=jsonOne.get('newTrustCreditorCode')
    officeAddress=jsonOne.get('officeAddress')
    onlineDate=jsonOne.get('onlineDate')
    payment=jsonOne.get('payment')
    paymode=jsonOne.get('paymode')
    platBackground=jsonOne.get('platBackground')
    platBackgroundDetail=jsonOne.get('platBackgroundDetail')
    platBackgroundDetailExpand=jsonOne.get('platBackgroundDetailExpand')
    platBackgroundExpand=jsonOne.get('platBackgroundExpand')
    platEarnings=jsonOne.get('platEarnings')
    platEarningsCode=jsonOne.get('platEarningsCode')
    platName=jsonOne.get('platName')
    platStatus=jsonOne.get('platStatus')
    platUrl=jsonOne.get('platUrl')
    problem=jsonOne.get('problem')
    problemTime=jsonOne.get('problemTime')
    recordId=jsonOne.get('recordId')
    recordLicId=jsonOne.get('recordLicId')
    registeredCapital=jsonOne.get('registeredCapital')
    riskCapital=jsonOne.get('riskCapital')
    riskFunds=jsonOne.get('riskFunds')
    riskReserve=jsonOne.get('riskReserve')
    riskcontrol=jsonOne.get('riskcontrol')
    securityModel=jsonOne.get('securityModel')
    securityModelCode=jsonOne.get('securityModelCode')
    securityModelOther=jsonOne.get('securityModelOther')
    serviceScore=jsonOne.get('serviceScore')
    serviceScoreDetail=jsonOne.get('serviceScoreDetail')
    startInvestmentAmout=jsonOne.get('startInvestmentAmout')
    term=jsonOne.get('term')
    termCodes=jsonOne.get('termCodes')
    termWeight=jsonOne.get('termWeight')
    transferExpense=jsonOne.get('transferExpense')
    transferExpenseDetail=jsonOne.get('transferExpenseDetail')
    trustCapital=jsonOne.get('trustCapital')
    trustCreditor=jsonOne.get('trustCreditor')
    trustCreditorMonth=jsonOne.get('trustCreditorMonth')
    trustFunds=jsonOne.get('trustFunds')
    tzjPj=jsonOne.get('tzjPj')
    vipExpense=jsonOne.get('vipExpense')
    withTzj=jsonOne.get('withTzj')
    withdrawExpense=jsonOne.get('withdrawExpense')
    sql='insert into problemPlatDetail (actualCapital,aliasName,association,associationDetail,autoBid,autoBidCode,bankCapital,bankFunds,bidSecurity,bindingFlag,businessType,companyName,credit,creditLevel,delayScore,delayScoreDetail,displayFlg,drawScore,drawScoreDetail,equityVoList,experienceScore,experienceScoreDetail,fundCapital,gjlhhFlag,gjlhhTime,gruarantee,inspection,juridicalPerson,locationArea,locationAreaName,locationCity,locationCityName,manageExpense,manageExpenseDetail,newTrustCreditor,newTrustCreditorCode,officeAddress,onlineDate,payment,paymode,platBackground,platBackgroundDetail,platBackgroundDetailExpand,platBackgroundExpand,platEarnings,platEarningsCode,platName,platStatus,platUrl,problem,problemTime,recordId,recordLicId,registeredCapital,riskCapital,riskFunds,riskReserve,riskcontrol,securityModel,securityModelCode,securityModelOther,serviceScore,serviceScoreDetail,startInvestmentAmout,term,termCodes,termWeight,transferExpense,transferExpenseDetail,trustCapital,trustCreditor,trustCreditorMonth,trustFunds,tzjPj,vipExpense,withTzj,withdrawExpense,platId) values ("'+actualCapital+'","'+aliasName+'","'+association+'","'+associationDetail+'","'+autoBid+'","'+autoBidCode+'","'+bankCapital+'","'+bankFunds+'","'+bidSecurity+'","'+bindingFlag+'","'+businessType+'","'+companyName+'","'+credit+'","'+creditLevel+'","'+delayScore+'","'+delayScoreDetail+'","'+displayFlg+'","'+drawScore+'","'+drawScoreDetail+'","'+equityVoList+'","'+experienceScore+'","'+experienceScoreDetail+'","'+fundCapital+'","'+gjlhhFlag+'","'+gjlhhTime+'","'+gruarantee+'","'+inspection+'","'+juridicalPerson+'","'+locationArea+'","'+locationAreaName+'","'+locationCity+'","'+locationCityName+'","'+manageExpense+'","'+manageExpenseDetail+'","'+newTrustCreditor+'","'+newTrustCreditorCode+'","'+officeAddress+'","'+onlineDate+'","'+payment+'","'+paymode+'","'+platBackground+'","'+platBackgroundDetail+'","'+platBackgroundDetailExpand+'","'+platBackgroundExpand+'","'+platEarnings+'","'+platEarningsCode+'","'+platName+'","'+platStatus+'","'+platUrl+'","'+problem+'","'+problemTime+'","'+recordId+'","'+recordLicId+'","'+registeredCapital+'","'+riskCapital+'","'+riskFunds+'","'+riskReserve+'","'+riskcontrol+'","'+securityModel+'","'+securityModelCode+'","'+securityModelOther+'","'+serviceScore+'","'+serviceScoreDetail+'","'+startInvestmentAmout+'","'+term+'","'+termCodes+'","'+termWeight+'","'+transferExpense+'","'+transferExpenseDetail+'","'+trustCapital+'","'+trustCreditor+'","'+trustCreditorMonth+'","'+trustFunds+'","'+tzjPj+'","'+vipExpense+'","'+withTzj+'","'+withdrawExpense+'","'+platId+'")'
    cur.execute(sql)
    conn.commit()

conn,cur=DatabaseUtil().getConn()
session=SessionUtil()
logUtil=LogUtil("problemPlatDetail.log")
cur.execute('select platId from problemPlat')
data=cur.fetchall()
print(data)
mylist=list()
print(data)
for i in range(0,len(data)):
    platId=str(data[i].get('platId'))
    
    mylist.append(platId)

print mylist  
for i in mylist:
    url='http://wwwservice.wdzj.com/api/plat/platData30Days?platId='+i
    try:
        data=session.getReq(url)
        platData=handleData(data)
        dictObject=DictUtil(platData)
        storeData(dictObject,conn,cur,i)
    except Exception,e:
        traceback.print_exc()
cur.close()
conn.close

На протяжении всего процесса мы конструируем запрос, а затем разбираем ответ каждого запроса, в котором возвращаемое значение json анализируется с помощью библиотеки json, а html-страница — с помощью библиотеки BeautifulSoup (html-страница со сложной структурой — рекомендуется использовать библиотеку lxml для разбора), анализируется до Результаты сохраняются в базе данных mysql.

Код рептилии

Кодовый адрес сканера(Примечание: код сканера может запускаться как на Python2, так и на python3. Я развертываю код сканера на сервере Alibaba Cloud и запускаю его с помощью Python2)

анализ данных

Анализ данных в основном использует Python numpy, pandas и matplotlib для анализа данных, дополненный Haizhi BDP.

анализ временных рядов

чтение данных

Как правило, данные считываются в DataFrame панд для анализа. Ниже приведен пример чтения данных с проблемной платформы.

problemPlat=pd.read_csv('problemPlat.csv',parse_dates=True)#问题平台 

структура данных

QQ截图20180123212641.png

анализ временных рядов

например, количество проблемных платформ меняется со временем

problemPlat['id']['2012':'2017'].resample('M',how='count').plot(title='P2P发生问题')#发生问题P2P平台数量 随时间变化趋势

Графический дисплей

QQ截图20180123212803.png

Географический анализ

В комплекте с Haizhi BDP (Python сложнее рисовать колеса раздачи карт, и я его еще не изучил)

Количество проблемных платформ в каждой провинции

下载.png

Оборот платформы по провинциям

全年成交额全国各省对比.png

Анализ распределения размеров

Например, распределение оборота платформы по стране в июне код

juneData['amount'].hist(normed=True)
juneData['amount'].plot(kind='kde',style='k--')#六月份交易量概率分布

Графическое отображение ядерной плотности

QQ截图20180123213700.png
Возьмем логарифмическое ядро ​​распределения плотности оборота

np.log10(juneData['amount']).hist(normed=True)
np.log10(juneData['amount']).plot(kind='kde',style='k--')#取 10 对数的 概率分布

Графический дисплей

QQ截图20180123213901.png
Можно видеть, что после логарифмирования 10 распределение больше соответствует нормальной форме пирамиды.

Корреляционный анализ

Например, тенденция изменения коэффициента корреляции между объемом транзакций Lufax и объемом транзакций на всех платформах.

lujinData=platVolume[platVolume['wdzjPlatId']==59]
corr=pd.rolling_corr(lujinData['amount'],allPlatDayData['amount'],50,min_periods=50).plot(title='陆金所交易额与所有平台交易额的相关系数变化趋势')

Графический дисплей

QQ截图20180123214114.png

Сравнение классификации

Сравнение данных об объеме транзакций между платформой автокредитования и всей платформой

carFinanceDayData=carFinanceData.resample('D').sum()['amount']
fig,axes=plt.subplots(nrows=1,ncols=2,sharey=True,figsize=(14,7))
carFinanceDayData.plot(ax=axes[0],title='车贷平台交易额')
allPlatDayData['amount'].plot(ax=axes[1],title='所有p2p平台交易额')

QQ截图20180123214359.png

Прогноз тренда

Например, предсказать тренд объема торгов Lufax (с помощью библиотеки Facebook Prophet)

lujinAmount=platVolume[platVolume['wdzjPlatId']==59]
lujinAmount['y']=lujinAmount['amount']
lujinAmount['ds']=lujinAmount['date']
m=Prophet(yearly_seasonality=True)
m.fit(lujinAmount)
future=m.make_future_dataframe(periods=365)
forecast=m.predict(future)
m.plot(forecast)

Графическое отображение прогноза тренда

QQ截图20180123214653.png

код анализа данных

Кодовый адрес анализа данных(Примечание: код анализа данных интеллектуально работает в среде Python3)Пример после запуска кода(Вы также можете просмотреть конкретное кодовое решение в графическом виде, не устанавливая среду Python)

постскриптум

Это первый проект, который я написал после того, как переключился с веб-сайта на Java на направление данных, а также это мой первый проект на Python.Во время всего процесса я не столкнулся со многими подводными камнями.В общем, краулер и анализ данных и языковые барьеры Python очень низкий. Если вы хотите начать работу с поисковым роботом Python, порекомендуйте «Сбор сетевых данных Python».

s29086659.jpg
Начало работы с Python, если вы хотите проанализировать данные, он рекомендовал «Использование Python для анализа данных».
30adcbef76094b360e72e763a9cc7cd98c109d58.jpg