## Step 1: Define the symbolic representation of the problem
Let's denote the number of crabs as $x_1$ and the number of lobsters as $x_2$. The profit per crab is $14, and the profit per lobster is $18. The time spent on cleaning crabs is 4 minutes and on lobsters is 5 minutes, with a total of 400 minutes available for cleaning. The time spent on shelling crabs is 15 minutes and on lobsters is 12 minutes, with a total of 900 minutes available for shelling.

## Step 2: Formulate the objective function
The objective function to maximize profit is $14x_1 + 18x_2$.

## 3: Formulate the constraints
The constraints based on the given resources are:
1. Cleaning time: $4x_1 + 5x_2 \leq 400$
2. Shelling time: $15x_1 + 12x_2 \leq 900$
Also, $x_1 \geq 0$ and $x_2 \geq 0$ because the number of crabs and lobsters cannot be negative.

## 4: Symbolic representation in JSON format
```json
{
'sym_variables': [('x1', 'crabs'), ('x2', 'lobsters')],
'objective_function': '14*x1 + 18*x2',
'constraints': ['4*x1 + 5*x2 <= 400', '15*x1 + 12*x2 <= 900', 'x1 >= 0', 'x2 >= 0']
}
```

## 5: Convert the problem into Gurobi code
```python
import gurobi

def solve_optimization_problem():
    # Create a new model
    model = gurobi.Model()

    # Define the variables
    x1 = model.addVar(name='crabs', lb=0, ub=gurobi.GRB.INFINITY)
    x2 = model.addVar(name='lobsters', lb=0, ub=gurobi.GRB.INFINITY)

    # Define the objective function
    model.setObjective(14*x1 + 18*x2, gurobi.GRB.MAXIMIZE)

    # Define the constraints
    model.addConstr(4*x1 + 5*x2 <= 400, name='cleaning_constraint')
    model.addConstr(15*x1 + 12*x2 <= 900, name='shelling_constraint')

    # Optimize the model
    model.optimize()

    # Print the solution
    if model.status == gurobi.GRB.OPTIMAL:
        print(f"Optimal number of crabs: {x1.varValue}")
        print(f"Optimal number of lobsters: {x2.varValue}")
        print(f"Maximum profit: {model.objVal}")
    else:
        print("The model is infeasible")

solve_optimization_problem()
```