scraping requests python http cookies authorization scraper

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:

  1. abrir un navegador, ir al sitio y buscar la página de inicio de sesión
  2. 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)
  3. 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