tl;dr: For a spacecraft orbiting the Earth within the 1.5 million kilometer Hill sphere, there will be plenty of opportunities to view a transit of Venus. Below I've done the calculation for central transits but it's not exhaustive; from the edge of the Hill sphere there will be even more transits across the edges of the Sun.
If I get time in the next few days I will add that to the search.
However: in the mean time if someone would like to implement that and post it as a new answer as an exercise, please feel free!
Next chance: June 1, 2028 at 850,000 km from Earth
2012, 2020, 2028, 2036 are all inferior conjunctions that will be central transits from Earth's Hill sphere. We missed 2020 but there's plenty of time to get a solar telescope into some fancy three-body orbit around Earth for an unprecedented view of a transit of Venus across the Sun in 2028.
@BrendanLuke15's answer is excellent and makes great use of JPL's Horizons interface. It's an incredibly powerful tool and once one learns to use the SPICE that powers it, the sky's the limit!
For a subset of the features available from Horizons there is the python package Skyfield which accesses the same JPL development ephemerides (and pronounciation) that Horizons & SPICE use.
Below I started with the prediction for the 2012 transit and looked 150 years in the future using the synodic period +/- 2 days, and that gave every inferior conjunction nicely.
$$T_{Syn} = 1 \ / \ ( \ 1 \ / \ T_{Venus} - 1 \ / \ T_{Earth}) = \frac{T_{Venus} \ T_{Earth}}{T_{Earth} - T_{Venus}}.$$
Because the solar system's planets interact with each other gravitationally and even more because the Earth's and Venus' orbits are slightly eccentric, there's some oscillations of the epoch of inferior conjunction relative to the synodic period of a day or so.
note: you can see that the December group is shifted by one day from the June group, likely due to eccentricities.
In the first two plots I've used Skyfield's .separation_from()
method to get the angular separation between Venus and either the Sun's center or edge in degrees.
In the last plot I drew a line from the Sun through Venus and calculated the closest distance that it passed Earth, so we could understand what an Earth-orbiting spacecraft might have a chance of seeing.
I limited the distance to 1.5 million kilometers, the Earth's Hill sphere within which we can talk about orbits that are somewhat stable to perturbations by the Sun. In reality one will still have to pay attention to station keeping out near the Hill sphere, but there are many, many kinds of three-body orbits possible besides the familliar halo orbits associated with Sun-Earth L1 and L2.
Here are the times when a line drawn through the centers of the Sun and Venus will pass through the Hill sphere.
I will leave it as an exercise for the reader to add to it the times when a ray from anywhere around the limb of the Sun does so, there will likely be some more, but they will be of shorter duration than a central transit.
Since the orbital planes of Earth and Venus intersect along the "June/December line" (which probably has a better name than that) we see that there are families of cis-lunar accessible transits clustered at eight year intervals in either June-ish or December-ish:
date (UTC) million km
2012-06-06 0.163
2020-06-03 0.508
2028-06-01 0.853
2036-05-30 1.196
2093-12-17 1.334
2101-12-16 0.954
2109-12-13 0.571
2117-12-11 0.189
2125-12-08 0.194
2133-12-06 0.576
2141-12-03 0.958
2149-12-01 1.338

Inelegant, non PEP-8 quickie script:
import numpy as np
import matplotlib.pyplot as plt
from skyfield.api import Loader
from skyfield.timelib import Time
loaddata = Loader('~/Documents/fishing/SkyData') # avoids multiple copies of large files
ts = loaddata.timescale() # include builtin=True if you want to use older files (you may miss some leap-seconds)
eph = loaddata('de405.bsp')
# https://rhodesmill.org/skyfield/api-position.html#skyfield.positionlib.ICRF.separation_from
# https://space.stackexchange.com/questions/53643/can-i-observe-a-venus-transit-before-2117-from-a-spacecraft-in-the-earth-moon-ne
# transit of June 05/06 2012
t0 = ts.utc(2012, 6, 6, 1, 29, 36.3) # https://eclipse.gsfc.nasa.gov/OH/transit12.html
# synodic period of Earth
Te = 365.2564 # days
Tv = 224.701 # days
Tsyn = 1/(1/Tv - 1/Te)
R_sun = 695700. # km
# approximate epochs of inferior conjunctions +/- 150 years
n = int(150 / (Tsyn/Te))
print('n: ', n)
epoch_JDs = t0.tt + np.arange(0, n+1) * Tsyn
sun, venus, earth = [eph[x] for x in ('sun', 'venus', 'earth')]
span = np.linspace(-1.5, 1, 100) #
separations, distances, earth_distances, minima, dates = [], [], [], [], []
for i, JD in enumerate(epoch_JDs):
times = ts.tt_jd(JD + span)
e = earth.at(times)
s, v = e.observe(sun), e.observe(venus)
sep = s.separation_from(v)
separations.append(sep.degrees)
distance = s.distance().km
distances.append(distance)
vs = venus - sun
vs_vector = vs.at(times).position.km
vs_normal = vs_vector / np.sqrt((vs_vector**2).sum(axis=0))
vpos = venus.at(times).position.km
epos = e.position.km
earth_vector = np.cross(vpos - epos, vs_normal, axis=0)
earth_distance = np.sqrt((earth_vector**2).sum(axis=0))
earth_distances.append(earth_distance)
minimum = np.argmax(-earth_distance)
minima.append(minimum)
date = Time.utc_strftime(times[minimum], format='%Y-%m-%d')
dates.append(date)
separations = np.vstack(separations)
distances = np.vstack(distances)
earth_distances = np.vstack(earth_distances)
half_angles = np.degrees(np.arctan2(R_sun, distances))
print('separations.shape: ', separations.shape)
if True:
titles = ('center of Sun', 'solar limb', 'approx Earth distance (central)')
fig, axes = plt.subplots(3, 1)
ax1, ax2, ax3 = axes
goodies = zip(separations, half_angles, earth_distances, minima, dates)
for sep, ha, ed, mi, da in goodies:
ed_mkm = ed / 1E+06 # millions of kilometers
ax1.plot(span, sep)
ax2.plot(span, sep-ha)
ax3.plot(span, ed_mkm)
if ed_mkm[mi] < 1.5:
print(' ', da, ' ', round(ed_mkm[mi], 3))
if int(da[:4]) > 2117:
ax3.text(span[mi], ed_mkm[mi], da, horizontalalignment='right')
else:
ax3.text(span[mi], ed_mkm[mi], da, horizontalalignment='left')
for ax, title in zip(axes, titles):
ax.set_title(title)
ax1.set_ylim(0, 2)
ax2.set_ylim(0, 2)
ax3.set_ylim(0, 1.5)
ax1.set_ylabel('degrees')
ax2.set_ylabel('degrees')
ax3.set_ylabel('millions of km')
ax3.set_xlabel('offset from synodic estimate (days)')
plt.show()