爬取网贷之家数据

198 阅读6分钟

爬取网贷之家数据

导入相关模块

import requests
import pandas as pd
import time
from fake_useragent import UserAgent
from bs4 import BeautifulSoup
import concurrent
import random

fake_useragent模块可以模拟请求头中地useragent信息,在使用request.get函数时相当于加入了浏览器地版本信息,这样远程服务器就不会简单地认定你为爬虫了。 这里使用ua = UserAgent()来调用。

concurrent模块是多线程模块,加入多线程可以提高爬取效率,具体使用过程以后再分析~

解析网页数据

先抛代码

def scrape_detail(url):
    result=pd.DataFrame(columns=['平台名称','平均利率','待还余额','注册地','上线时间','网友印象','综合评分','标签'])    
    time.sleep(random.uniform(0,2))
    print('正在下载 : %s' %url)
    headers={'User-Agent' : ua.random,
                 'Cookie':cookies}
    data=requests.get(url,headers=headers)
    soup = BeautifulSoup(data.content,'lxml')
    data_list=soup.find_all('li',{'class':'item'})
    for each in data_list:
        item={}
        item['平台名称']=each.find('h2').get_text().replace('\n','')
        item['平均利率']=each.find('div',{'class':'itemConBox'}).find('em').get_text()
        item['待还余额']=each.find_all('div',{'class':'itemConBox'})[1].get_text().split(':')[1]
        item['注册地']=each.find_all('div',{'class':'itemConBox'})[2].get_text().split(':')[1]
        item['上线时间']=each.find_all('div',{'class':'itemConBox'})[3].get_text().split(':')[1]
        impression=each.find('div',{'class':'itemConBox bgBox'}).find_all('span')
        impression_list=[]
        for everyone in impression:
            impression_list.append(everyone.get_text())
        item['网友印象']=impression_list
        item['综合评分']=each.find('div',{'class':'itemConBox bgBox'}).find('strong').get_text()
        tag=each.find_all('div',{'class':'itemTitleTag tag'})
        tag_list=[]
        for everyone in tag:
            tag_list.append(everyone.find('em').get_text())
        item['标签']=tag_list
        result=result.append(item,ignore_index=True)
    return result

把爬取网页信息封装成函数,方便后面地调用。 本次我们准备爬取网贷之家中所有p2p平台(www.wdzj.com/dangan/sear…)的基础信息,首先要观察一下网页的结构,然后再进行爬取分析。

在网页中我们看到平台的信息包括平台名称平均利率待还余额等等,把这些都作为到result的列名称,然后用BeautifulSoup模块中的函数进行爬取。BeautifulSoup模块是常见的分析网页HTML代码结构的工具,类似的还有pyquery,两者使用方法基本相同,具体使用方法后续有时间再做解析。

构建线程池

def Myfutures(func,url_list,num_of_max_works=10):
    with concurrent.futures.ThreadPoolExecutor(max_workers=num_of_max_works) as executor:
        res=[executor.submit(func, i) for i in url_list]
        return res

构建线程池,提高爬取效率。这里默认使用了10个线程,同时能够返回每一个线程的运行结果。

爬取运营中、停业或转型、问题平台

### 爬取运营中平台
def platform_running():
    print('正在下载“运营中”的平台信息'.center(60,'='))
    result=pd.DataFrame(columns=['平台名称','平均利率','待还余额','注册地','上线时间','网友印象','综合评分','标签'])
    url_list=['https://www.wdzj.com/dangan/search?filter=e1&sort=1&currentPage=' + str(i) for i in range(1,14)]
    for i in url_list:
        data=scrape_detail(i)
        result=pd.concat([result,data])
        time.sleep(2)
    print('“运营中”的平台信息下载完成'.center(60,'='))
    return result

### 爬取停业或者转型平台
def platform_closed_or_Transformation():
    print('正在下载“停业或转型”的平台信息'.center(60,'='))
    result=pd.DataFrame(columns=['平台名称','平均利率','待还余额','注册地','上线时间','网友印象','综合评分','标签'])
    url_list=['https://www.wdzj.com/dangan/search?filter=e2&sort=1&currentPage=' + str(i) for i in range(1,130)]
    res=Myfutures(scrape_detail,url_list)
    for future in concurrent.futures.as_completed(res):
        data=future.result()
        result=pd.concat([result,data])
    print('“停业或转型”的平台信息下载完成'.center(60,'='))
    return result

### 爬取问题平台
def platform_introuble():
    print('正在下载“出现问题”的平台信息'.center(60,'='))
    result=pd.DataFrame(columns=['平台名称','平均利率','待还余额','注册地','上线时间','网友印象','综合评分','标签'])
    url_list=['https://www.wdzj.com/dangan/search?filter=e3&sort=1&currentPage=' + str(i) for i in range(1,118)]
    res=Myfutures(scrape_detail,url_list)
    for future in concurrent.futures.as_completed(res):
        data=future.result()
        result=pd.concat([result,data])   
    print('“出现问题”的平台信息下载完成'.center(60,'='))
    return result

每一个函数中都调用了前面定义的scrape_detail函数,三个函数结构基本相同,区别是第一个函数并没有加入多线程,最后在运行代码阶段,以此来对比一下是否加入多线程对爬取效果的影响。

存储数据并运行

def save_data():
    with pd.ExcelWriter(r'网贷之家1.xlsx') as writer:
        sheet_list=['运营中','停业或转型','问题平台']
        result=platform_running()
        result.to_excel(writer,index=None,sheet_name=sheet_list[0])
        result=platform_closed_or_Transformation()
        result.to_excel(writer,index=None,sheet_name=sheet_list[1])
        result=platform_introuble()
        result.to_excel(writer,index=None,sheet_name=sheet_list[2])

if __name__ == '__main__': 
    save_data()

把爬取出的数据表都放入到一个excel中,表名分别为运营中,停业或转型,问题平台,开始运行,运行时间大概在2~3分钟。

全部代码如下

# -*- coding: utf-8 -*-
"""
Created on Fri Apr 24 16:18:28 2020

@author: wangyan
"""

import requests
import pandas as pd
import time
from fake_useragent import UserAgent
from bs4 import BeautifulSoup
import concurrent
import random

cookies='JSESSIONID=65389AB324B502E2336723462331362C; __jsluid_s=6987a7bb2700b9aa213e68fb221f8a78; __jsluid_h=0b27cd8385354fa0949042062c783d67; wdzj_session_source=https%253A%252F%252Fwww.wdzj.com%252Fdangan%252Fsearch%253Ffilter%253De1%2526currentPage%253D1; WDZJptlbs=1; Hm_lvt_9e837711961994d9830dcd3f4b45f0b3=1587711532; _pk_ses.1.b30f=*; gr_user_id=7dd31ff2-6d1b-4f1e-8fd5-7d8641798352; gr_session_id_1931ea22324b4036a653ff1d3a0b4693=793a392e-21c7-46fb-861d-8c9616e94f02; gr_session_id_1931ea22324b4036a653ff1d3a0b4693_793a392e-21c7-46fb-861d-8c9616e94f02=true; _ga=GA1.2.844346962.1587711532; _gid=GA1.2.198712134.1587711532; PHPSESSID=lsf4g1044lqk8rqs8ajin318h3; Hm_lpvt_9e837711961994d9830dcd3f4b45f0b3=1587712229; _pk_id.1.b30f=3a9dbc19cb62c72c.1587711532.1.1587712229.1587711532.; _gat=1'
ua = UserAgent()


### 解析网页信息
def scrape_detail(url):
    result=pd.DataFrame(columns=['平台名称','平均利率','待还余额','注册地','上线时间','网友印象','综合评分','标签'])    
    time.sleep(random.uniform(0,2))
    print('正在下载 : %s' %url)
    headers={'User-Agent' : ua.random,
                 'Cookie':cookies}
    data=requests.get(url,headers=headers)
    soup = BeautifulSoup(data.content,'lxml')
    data_list=soup.find_all('li',{'class':'item'})
    for each in data_list:
        item={}
        item['平台名称']=each.find('h2').get_text().replace('\n','')
        item['平均利率']=each.find('div',{'class':'itemConBox'}).find('em').get_text()
        item['待还余额']=each.find_all('div',{'class':'itemConBox'})[1].get_text().split(':')[1]
        item['注册地']=each.find_all('div',{'class':'itemConBox'})[2].get_text().split(':')[1]
        item['上线时间']=each.find_all('div',{'class':'itemConBox'})[3].get_text().split(':')[1]
        impression=each.find('div',{'class':'itemConBox bgBox'}).find_all('span')
        impression_list=[]
        for everyone in impression:
            impression_list.append(everyone.get_text())
        item['网友印象']=impression_list
        item['综合评分']=each.find('div',{'class':'itemConBox bgBox'}).find('strong').get_text()
        tag=each.find_all('div',{'class':'itemTitleTag tag'})
        tag_list=[]
        for everyone in tag:
            tag_list.append(everyone.find('em').get_text())
        item['标签']=tag_list
        result=result.append(item,ignore_index=True)
    return result

### 构建线程池
def Myfutures(func,url_list,num_of_max_works=10):
    with concurrent.futures.ThreadPoolExecutor(max_workers=num_of_max_works) as executor:
        res=[executor.submit(func, i) for i in url_list]
        return res


### 爬取运营中平台
def platform_running():
    print('正在下载“运营中”的平台信息'.center(60,'='))
    result=pd.DataFrame(columns=['平台名称','平均利率','待还余额','注册地','上线时间','网友印象','综合评分','标签'])
    url_list=['https://www.wdzj.com/dangan/search?filter=e1&sort=1&currentPage=' + str(i) for i in range(1,14)]
    for i in url_list:
        data=scrape_detail(i)
        result=pd.concat([result,data])
        time.sleep(2)
    print('“运营中”的平台信息下载完成'.center(60,'='))
    return result

### 爬取停业或者转型平台
def platform_closed_or_Transformation():
    print('正在下载“停业或转型”的平台信息'.center(60,'='))
    result=pd.DataFrame(columns=['平台名称','平均利率','待还余额','注册地','上线时间','网友印象','综合评分','标签'])
    url_list=['https://www.wdzj.com/dangan/search?filter=e2&sort=1&currentPage=' + str(i) for i in range(1,130)]
    res=Myfutures(scrape_detail,url_list)
    for future in concurrent.futures.as_completed(res):
        data=future.result()
        result=pd.concat([result,data])
    print('“停业或转型”的平台信息下载完成'.center(60,'='))
    return result

### 爬取问题平台
def platform_introuble():
    print('正在下载“出现问题”的平台信息'.center(60,'='))
    result=pd.DataFrame(columns=['平台名称','平均利率','待还余额','注册地','上线时间','网友印象','综合评分','标签'])
    url_list=['https://www.wdzj.com/dangan/search?filter=e3&sort=1&currentPage=' + str(i) for i in range(1,118)]
    res=Myfutures(scrape_detail,url_list)
    for future in concurrent.futures.as_completed(res):
        data=future.result()
        result=pd.concat([result,data])   
    print('“出现问题”的平台信息下载完成'.center(60,'='))
    return result
   
### 存储数据
def save_data():
    with pd.ExcelWriter(r'网贷之家1.xlsx') as writer:
        sheet_list=['运营中','停业或转型','问题平台']
        result=platform_running()
        result.to_excel(writer,index=None,sheet_name=sheet_list[0])
        result=platform_closed_or_Transformation()
        result.to_excel(writer,index=None,sheet_name=sheet_list[1])
        result=platform_introuble()
        result.to_excel(writer,index=None,sheet_name=sheet_list[2])

if __name__ == '__main__': 
    save_data()
    

最后,代码写的比较匆忙,也没有加入代理信息,确实有点糙,以后再改进。

python小白,不喜勿喷!