爬虫实战:csrf问题,dataframe存储到MongoDB

本文主要爬虫爬取过程中遇到csrf的问题,以及如何将表格数据保存到MongoDB数据库。

爬取目标

目标url:https://www.ctic.org/crm/?action=result
爬虫实战:csrf问题,dataframe存储到MongoDB_第1张图片
如上图选项,点击view summary,则到了下面的界面,
爬虫实战:csrf问题,dataframe存储到MongoDB_第2张图片
这里我们就是爬取这个表格,不过是1989年到2011年的表格。

CSRF

在爬取https://www.ctic.org/crm?tdsourcetag=s_pctim_aiomsg这一网站的表格数据时,查看网页源代码,发现点击view summary按钮之后,发现这里的请求方式是post,并且提交的参数有一个_csrf,这个参数是什么呢,我搜索了一下,得到了答案,这里贴出一个详细CSRF讲解的链接
大概的讲一下:
CSRF跨站点请求伪造(Cross—Site Request Forgery),大概就是,你在上网的过程中,输入用户名密码登陆了A网站,然后A网站会返回你cookie让你在这个浏览器页面下可以继续以已登陆状态使用A网站的业务,然后你浏览了B网站,此时你的cookie也就发送到了B网站,B网站很坏,携带你的cookie发送请求到A网站,以你的身份来执行A网站的业务。
目前防御 CSRF 攻击主要有三种策略:验证 HTTP Referer 字段;在请求地址中添加 token 并验证;在 HTTP 头中自定义属性并验证。
在我们这次爬取中,是类似于第二种情况,在post提交表单请求时需要提交一个_csrf参数,这个参数是在之前的get请求时随记生成,由response返回给用户浏览器。
在这里插入图片描述
(查看网页源代码发现)
所以,在爬取过程中,我们需要先get请求这个url,然后从返回的html中提取csrf_token,然后再将此参数携带以post方式发起请求,当服务器接收到请求后,将其中csrf_token提取出来与session中的csrf_token对比,一致时才会执行对应业务。

DataFrame存储到MongoDB

在获取到了我们想要的页面之后,我们利用pandas.read_html()方法,该方法会获取当前页面的所有表格,经过尝试之后发现第一个就是我们想要获取的结果(从0开始索引),然后print一下type,发现我们想要获取的表格数据的type是DataFrame。
DataFrame是一种表格型数据结构,它含有一组有序的列,每列可以是不同的值。DataFrame既有行索引,也有列索引,它可以看作是由Series组成的字典,不过这些Series公用一个索引。我们这里因为要爬取1989到2011的数据,所以这里给数据添加一列year用以区分年份。
之后将其转换为json格式,提取其中的value,存入MongoDB
具体代码见下节

代码

#4.13
#keyword:csrf,dataframe,mongodb

import requests
from lxml import etree
import pandas as pd
import pymongo
import json
import time

url='https://www.ctic.org/crm?tdsourcetag=s_pctim_aiomsg'

headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36 Edg/80.0.361.111'
           'AppleWebKit/537.36 (KHTML, like Gecko) '
           'Chrome/74.0.3729.131 Safari/537.36',
           'Host': 'www.ctic.org'}

data = {
        'CRMSearchForm[year]': '1989',
        'CRMSearchForm[format]': 'Acres',
        'CRMSearchForm[area]': 'County',
        'CRMSearchForm[region]': 'Midwest',
        'CRMSearchForm[state]': 'IL',
        'CRMSearchForm[county]': 'Adams',
        'CRMSearchForm[crop_type]': 'All',
        'summary': 'county'}

#获取csfr_token和年份列表,并更新session
#参数:session
def get_info(session):
    #先以get方式请求
    resp = session.get(url=url, headers=headers)
    html = etree.HTML(resp.text)
    #获取csrf_token
    csrf_token = html.xpath('/html/head/meta[3]/@content')
    #获取年份列表
    years = html.xpath('//*[@id="crmsearchform-year"]/option/text()')
    data.update({'_csrf': csrf_token})
    return session,years

#获取页面数据
#参数1,:session;参数2:年份,int
def get_data(session,year):
    data.update({'CRMSearchForm[year]':year})
    resp = session.post(url, data=data, headers=headers)
    return resp,session


#获取数据库连接
def get_collection():
    mongo_client = pymongo.MongoClient('localhost', 27017)
    db = mongo_client['spider']
    ctic = db['ctic']
    return ctic


#参数1:mongdb连接;参数2:response;参数3:年份
def save_to_mongodb(collection,resp,year):
    if resp:
        #读取表格
        data = pd.read_html(resp.text)
        #插入新的列 显示年份
        (data[0])['year'] = year
        collection.insert(json.loads(data[0].T.to_json()).values())
        #flag为true说明本年份没问题,否则为flase,则继续爬一次
        print('存储成功:'+str(year))



if __name__=='__main__':
    session = requests.session()
    session,years = get_info(session)
    collection = get_collection()
    for year in years:
        resp, session = get_data(session, year)
        save_to_mongodb(collection, resp, year)
        time.sleep(1)


    print('`````````````````')
    print('done!')

MongoDB存储情况:
爬虫实战:csrf问题,dataframe存储到MongoDB_第3张图片
参考链接:

  • https://cuiqingcai.com/6829.html
  • http://www.phpddt.com/reprint/csrf.html

你可能感兴趣的:(爬虫,python,mongodb,爬虫,数据库,csrf)