The solution is setting up an array with the key being the order's item_id (note that this is not the same as product_id, it is a unique identifier).
Let's say you have an order $increment_id (order number):
$order = Mage::getModel('sales/order')->loadByIncrementId($increment_id);
$items = $order->getItemsCollection();
$qtys = array(); //this will be used for processing the invoice
foreach($items as $item){
$qty_to_invoice = x; //where x is the amount you wish to invoice
<!-- please note that if you don't want to invoice this product, set this value to 0 -->
$qtys[$item->getId()] = $qty_to_invoice;
<!-- Note that the ->getId() method gets the item_id on the order, not the product_id -->
}
$invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice($qtys);
<!-- The rest is only required when handling a partial invoice as in this example-->
$amount = $invoice->getGrandTotal();
$invoice->register()->pay();
$invoice->getOrder()->setIsInProcess(true);
$history = $invoice->getOrder()->addStatusHistoryComment(
'Partial amount of $' . $amount . ' captured automatically.', false
);
$history->setIsCustomerNotified(true);
$order->save();
Mage::getModel('core/resource_transaction')
->addObject($invoice)
->addObject($invoice->getOrder())
->save();
$invoice->save();
$invoice->sendEmail(true, ''); //set this to false to not send the invoice via email