requests - Cómo rozar un sitio web que requiere iniciar sesión primero con Python
requests login python (3)
Antes que nada, creo que vale la pena decirlo, sé que hay un montón de preguntas similares, pero NINGUNAS de ellas me funcionan ...
Soy un novato en Python, html y web scraper. Estoy tratando de eliminar la información del usuario de un sitio web que necesita iniciar sesión primero. En mis pruebas utilizo raspador mi configuración de correo electrónico de github como ejemplos. La página principal es '' https://github.com/login '' y la página de destino es '' https://github.com/settings/emails ''
Aquí hay una lista de métodos que he probado
##################################### Method 1
import mechanize
import cookielib
from BeautifulSoup import BeautifulSoup
import html2text
br = mechanize.Browser()
cj = cookielib.LWPCookieJar()
br.set_cookiejar(cj)
# Browser options
br.set_handle_equiv(True)
br.set_handle_gzip(True)
br.set_handle_redirect(True)
br.set_handle_referer(True)
br.set_handle_robots(False)
br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1)
br.addheaders = [(''User-agent'', ''Chrome'')]
# The site we will navigate into, handling it''s session
br.open(''https://github.com/login'')
for f in br.forms():
print f
br.select_form(nr=0)
# User credentials
br.form[''login''] = ''myusername''
br.form[''password''] = ''mypwd''
# Login
br.submit()
br.open(''github.com/settings/emails'').read()
################ Method 2
import urllib, urllib2, cookielib
username = ''myusername''
password = ''mypwd''
cj = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
login_data = urllib.urlencode({''username'' : username, ''j_password'' : password})
opener.open(''https://github.com/login'', login_data)
resp = opener.open(''https://github.com/settings/emails'')
print resp.read()
############# Method 3
import urllib
opener = urllib.FancyURLopener()
print opener.open(''http://myusername:[email protected]/settings/emails'').read()
########## Method 4
import mechanize
import cookielib
br = mechanize.Browser()
cj = cookielib.LWPCookieJar()
br.set_cookiejar(cj)
br.set_handle_equiv(True)
br.set_handle_gzip(True)
br.set_handle_redirect(True)
br.set_handle_referer(True)
br.set_handle_robots(False)
br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1)
#br.set_debug_http(True)
#br.set_debug_redirects(True)
#br.set_debug_responses(True)
br.addheaders = [(''User-agent'', ''Chrome'')]
br.add_password(''https://github.com/settings/emails'', ''myusername'', ''mypwd'')
br.open(''https://github.com/settings/emails'')
print br.response().read()
############ Methods 5
from requests import session
payload = {
''action'': ''login'',
''username'': ''myusername'',
''password'': ''mypwd''
}
with session() as c:
c.post(''https://github.com/login'', data=payload)
request = c.get(''https://github.com/settings/emails'')
print request.headers
print request.text
########### Method 6
import requests
from requests.packages.urllib3 import add_stderr_logger
import sys
from bs4 import BeautifulSoup as bs
add_stderr_logger()
s = requests.Session()
s.headers[''User-Agent''] = ''Chrome''
username = ''myusername''
password = ''mypwd''
url = ''https://github.com/login''
# after examining the HTML of the website you''re trying to log into
# set name_form to the name of the form element that contains the name and
# set password_form to the name of the form element that will contain the password
login = {''login'': username, ''password'': password}
login_response = s.post(url, data=login)
for r in login_response.history:
if r.status_code == 401: # 401 means authentication failed
print ''error!''
sys.exit(1) # abort
pdf_response = s.get(''https://github.com/settings/emails'') # Your cookies and headers are automatically included
soup = bs(pdf_response.content)
También he leído algunas discusiones sobre las diferencias entre la Autenticación HTTP y las cookies. Todavía ninguno de ellos funcionó.
Por favor ayuda y cualquier ayuda sería apreciada. Muchas gracias.
Esto funciona para mí:
##################################### Method 1
import mechanize
import cookielib
from BeautifulSoup import BeautifulSoup
import html2text
# Browser
br = mechanize.Browser()
# Cookie Jar
cj = cookielib.LWPCookieJar()
br.set_cookiejar(cj)
# Browser options
br.set_handle_equiv(True)
br.set_handle_gzip(True)
br.set_handle_redirect(True)
br.set_handle_referer(True)
br.set_handle_robots(False)
br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1)
br.addheaders = [(''User-agent'', ''Chrome'')]
# The site we will navigate into, handling it''s session
br.open(''https://github.com/login'')
# View available forms
for f in br.forms():
print f
# Select the second (index one) form (the first form is a search query box)
br.select_form(nr=1)
# User credentials
br.form[''login''] = ''mylogin''
br.form[''password''] = ''mypass''
# Login
br.submit()
print(br.open(''https://github.com/settings/emails'').read())
¡No estabas lejos en absoluto!
La forma clásica de abordar este problema es:
- abrir un navegador, ir al sitio y buscar la página de inicio de sesión
- inspeccione el código fuente de la página para averiguar: I. cuál es el formulario de inicio de sesión (una página puede tener muchos formularios, pero generalmente uno de ellos es el formulario de inicio de sesión) II. cuáles son los nombres de campo utilizados para el nombre de usuario y la contraseña (pueden variar mucho) III. si hay otros campos que se deben enviar (como un token de autenticación)
- escriba la araña de Scrapy para replicar el envío del formulario usando FormRequest
Siendo fanáticos de la automatización, pensamos que podríamos escribir algunos códigos para automatizar el punto 2 (que en realidad consume más tiempo) y el resultado es un formulario de inicio de sesión, una biblioteca que completa automáticamente los formularios de inicio de sesión con la página de inicio de sesión, el nombre de usuario y la contraseña. Aquí está el código de una araña simple que usaría el formulario de inicio de sesión para iniciar sesión en los sitios automáticamente.
githubloginspider.py
from scrapy.spider import BaseSpider
from scrapy.http import FormRequest
from scrapy.http.request import Request
from loginform import fill_login_form
from scrapy import log
from scraping.articles import ArticleItem
class GitHubLogin(BaseSpider):
name = ''GitHubLogin''
allowed_domains = [''github.com'']
start_urls = [''http://github.com/login'']
login_user = ''ranvijay5686''
login_pass = ''''
def parse(self, response):
(args, url, method) = fill_login_form(response.url,
response.body, self.login_user, self.login_pass)
return FormRequest(url, method=method, formdata=args,
callback=self.after_login)
def after_login(self, response):
# for link in response.xpath("//*[@id=''site-container'']/div[2]/div[4]/p/a/@href").extract():
item = ArticleItem()
item[''title''] = ''ranvijay''
log.msg(''*************** : ''
+ str(response.xpath("//form[@class=''subnav-search left'']/input/@value"
).extract()))
item[''url''] = /
response.xpath("//*[@id=''site-container'']/div[1]/div/div/span/span/text()"
).extract()
yield item
items.py
from scrapy.item import Item, Field
class ArticleItem(Item):
title = Field()
url = Field()
loginform.py
import sys
from argparse import ArgumentParser
from collections import defaultdict
from lxml import html
__version__ = ''1.0'' # also update setup.py
def _form_score(form):
score = 0
# In case of user/pass or user/pass/remember-me
if len(form.inputs.keys()) in (2, 3):
score += 10
typecount = defaultdict(int)
for x in form.inputs:
type_ = (x.type if isinstance(x, html.InputElement) else ''other''
)
typecount[type_] += 1
if typecount[''text''] > 1:
score += 10
if not typecount[''text'']:
score -= 10
if typecount[''password''] == 1:
score += 10
if not typecount[''password'']:
score -= 10
if typecount[''checkbox''] > 1:
score -= 10
if typecount[''radio'']:
score -= 10
return score
def _pick_form(forms):
"""Return the form most likely to be a login form"""
return sorted(forms, key=_form_score, reverse=True)[0]
def _pick_fields(form):
"""Return the most likely field names for username and password"""
userfield = passfield = emailfield = None
for x in form.inputs:
if not isinstance(x, html.InputElement):
continue
type_ = x.type
if type_ == ''password'' and passfield is None:
passfield = x.name
elif type_ == ''text'' and userfield is None:
userfield = x.name
elif type_ == ''email'' and emailfield is None:
emailfield = x.name
return (userfield or emailfield, passfield)
def submit_value(form):
"""Returns the value for the submit input, if any"""
for x in form.inputs:
if x.type == ''submit'' and x.name:
return [(x.name, x.value)]
else:
return []
def fill_login_form(
url,
body,
username,
password,
):
doc = html.document_fromstring(body, base_url=url)
form = _pick_form(doc.xpath(''//form''))
(userfield, passfield) = _pick_fields(form)
form.fields[userfield] = username
form.fields[passfield] = password
form_values = form.form_values() + submit_value(form)
return (form_values, form.action or form.base_url, form.method)
def main():
ap = ArgumentParser()
ap.add_argument(''-u'', ''--username'', default=''username'')
ap.add_argument(''-p'', ''--password'', default=''secret'')
ap.add_argument(''url'')
args = ap.parse_args()
try:
import requests
except ImportError:
print ''requests library is required to use loginform as a tool''
r = requests.get(args.url)
(values, action, method) = fill_login_form(args.url, r.text,
args.username, args.password)
print ''''''url: {0}
method: {1}
payload:''''''.format(action, method)
for (k, v) in values:
print ''- {0}: {1}''.format(k, v)
if __name__ == ''__main__'':
sys.exit(main())
Me encantaría agregar mi solución al costado. esta respuesta sigue principalmente el enfoque hacky / perezoso que siempre sigo en todo lo que hago. Continué con principalmente porque, yo era demasiado vago para manejar las cookies, los datos de sesión, etc.
esta solución es de lo más útil si desea raspar varias páginas de un sitio web después de iniciar sesión con credenciales de cuenta única (por ejemplo, todas sus pinterest boards). no si desea automatizar la autenticación usando múltiples cuentas
entonces mi solución es el selenio junto con los perfiles de Firefox.
- Cree un nuevo perfil de Firefox para crear un nuevo perfil de Firefox, tenga en cuenta la ubicación donde está almacenado, abra Firefox en el perfil correspondiente. e inicie sesión en el sitio web de forma manual. detalles sobre los perfiles de Firefox
- Ahora usa selenio con este perfil Selenium Session usará cookies y datos de sesión del perfil de Firefox para que tu autentificación permanezca.
ideé este mecanismo cuando me encontré con la necesidad de raspar algunas páginas de pinterest, he agregado algunas líneas de código de la muestra que muestra cómo usar el perfil. adaptarse al código de acuerdo a sus necesidades.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
#replace with your firefox profile
fp=webdriver.FirefoxProfile(''C:/Users/SJ/AppData/Roaming/Mozilla/Firefox/Profiles/hlsfrs2o.scrape'')
#enter your url here
url=""
driver = webdriver.Firefox(fp)
driver.get(url)
html_source = driver.page_source