The Zapper simply reports if it detects light or not at the very instant you read from its controller port. Since a CRT doesn't draw the frame all at once, you can continuously read the Zapper every scanline, keeping track of how many scanlines have passed, until the Zapper detects light. You can reliably get the Zapper's Y-coordinate in a single frame this way.
Attempting a similar technique to grab the X-coordinate is unfortunately unreliable, as not only are there horizontal gaps in-between input reads, but the Zapper can pick up stray light from earlier in the scanline. So you will get a fairly noisy X-coordinate.
So my technique is thus:
1. Flash the entire canvas a bright color and poll the Zapper each scanline for the Y-coordinate.
2. If we get a valid Y-Coordinate, turn the canvas black and display a bright box at the given Y-coordinate at the left side of the canvas. Each frame, move this box to the right until either the Zapper detects light, or the box has reached the other side of the canvas.
This is the same technique the NES ports of Operation Wolf and Lethal Enforcers use, though the size of their X-coordinate detection boxes are much larger. I've limited mine to 32 pixels horizontally for a better balance of granularity and speed. I felt anything more than 8 frames to determine the X-coordinate was too slow.