ข้อผิดพลาด HTTP 403 ใน Python 3 Web Scraping


107

ฉันพยายามคัดลอกเว็บไซต์เพื่อฝึกฝน แต่ฉันยังคงได้รับ HTTP Error 403 (คิดว่าฉันเป็นบอท) หรือไม่?

นี่คือรหัสของฉัน:

#import requests
import urllib.request
from bs4 import BeautifulSoup
#from urllib import urlopen
import re

webpage = urllib.request.urlopen('http://www.cmegroup.com/trading/products/#sortField=oi&sortAsc=false&venues=3&page=1&cleared=1&group=1').read
findrows = re.compile('<tr class="- banding(?:On|Off)>(.*?)</tr>')
findlink = re.compile('<a href =">(.*)</a>')

row_array = re.findall(findrows, webpage)
links = re.finall(findlink, webpate)

print(len(row_array))

iterator = []

ข้อผิดพลาดที่ฉันได้รับคือ:

 File "C:\Python33\lib\urllib\request.py", line 160, in urlopen
    return opener.open(url, data, timeout)
  File "C:\Python33\lib\urllib\request.py", line 479, in open
    response = meth(req, response)
  File "C:\Python33\lib\urllib\request.py", line 591, in http_response
    'http', request, response, code, msg, hdrs)
  File "C:\Python33\lib\urllib\request.py", line 517, in error
    return self._call_chain(*args)
  File "C:\Python33\lib\urllib\request.py", line 451, in _call_chain
    result = func(*args)
  File "C:\Python33\lib\urllib\request.py", line 599, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 403: Forbidden

คำตอบ:


229

อาจเป็นเพราะmod_securityหรือคุณสมบัติการรักษาความปลอดภัยของเซิร์ฟเวอร์ที่คล้ายกันซึ่งบล็อกตัวแทนผู้ใช้สไปเดอร์ / บอทที่รู้จัก ( urllibใช้บางอย่างเช่นpython urllib/3.3.0ตรวจพบได้ง่าย) ลองตั้งค่าตัวแทนผู้ใช้เบราว์เซอร์ที่รู้จักด้วย:

from urllib.request import Request, urlopen

req = Request('http://www.cmegroup.com/trading/products/#sortField=oi&sortAsc=false&venues=3&page=1&cleared=1&group=1', headers={'User-Agent': 'Mozilla/5.0'})
webpage = urlopen(req).read()

สิ่งนี้ใช้ได้กับฉัน

อย่างไรก็ตามในรหัสของคุณคุณไม่มีส่วน()หลัง.readในไฟล์urlopenบรรทัด แต่ฉันคิดว่ามันพิมพ์ผิด

เคล็ดลับ: เนื่องจากนี่คือแบบฝึกหัดให้เลือกไซต์อื่นที่ไม่ จำกัด บางทีพวกเขาอาจจะปิดกั้นurllibด้วยเหตุผลบางอย่าง ...


ฉันถือว่าปลอดภัยที่จะใช้ซ้ำreqสำหรับการurlopenโทรหลายครั้ง
Acumenus

1
อาจจะสายไปหน่อย แต่ฉันมี User-Agent ในรหัสของฉันอยู่แล้ว แต่ก็ยังให้ฉันError 404: Access denied
Reema Parakh

วิธีนี้ใช้ได้ผล แต่ฉันรู้สึกว่าพวกเขาต้องมีเหตุผลที่ดีในการบล็อกบอทและฉันละเมิดข้อกำหนดในการให้บริการ
xjcl

39

แน่นอนว่าเป็นการปิดกั้นเนื่องจากการใช้ urllib ของคุณตาม User Agent สิ่งเดียวกันนี้เกิดขึ้นกับฉันกับ OfferUp คุณสามารถสร้างคลาสใหม่ชื่อ AppURLopener ซึ่งแทนที่ user-agent ด้วย Mozilla

import urllib.request

class AppURLopener(urllib.request.FancyURLopener):
    version = "Mozilla/5.0"

opener = AppURLopener()
response = opener.open('http://httpbin.org/user-agent')

ที่มา


2
คำตอบด้านบนไม่ได้ผลสำหรับฉันในขณะที่คุณทำ ขอบคุณมาก!
Tarun Uday

ใช้งานได้ดี แต่ฉันต้องแนบการกำหนดค่า ssl กับสิ่งนี้ ฉันต้องทำอย่างไร ก่อนที่ฉันจะเพิ่มเป็นพารามิเตอร์ที่สอง (urlopen (request, context = ctx))
Hauke

2
ดูเหมือนว่ามันจะเปิดขึ้น แต่มันขึ้นว่า 'ValueError: read of closed file'
Martian2049

@zeta คุณจัดการขูด OfferUp และระบุพิกัดทางภูมิศาสตร์ที่จำเป็นเพื่อทำการค้นหาจากสคริปต์ได้อย่างไร
CJ Travis

@CJTravis ฉันไม่ได้ขูด OfferUp ฉันเพิ่งเรียกค่ารายการตาม URL ที่แน่นอนของรายการ ที่ไม่ต้องการพิกัดทางภูมิศาสตร์สำหรับฉัน
zeta

14

"นี่อาจเป็นเพราะmod_securityหรือคุณลักษณะความปลอดภัยของเซิร์ฟเวอร์ที่คล้ายกันซึ่งบล็อกที่รู้จัก

แมงมุม / บอท

ตัวแทนผู้ใช้ (urllib ใช้บางอย่างเช่น python urllib / 3.3.0 ซึ่งตรวจพบได้ง่าย) "- ตามที่ Stefano Sanfilippo กล่าวไว้แล้ว

from urllib.request import Request, urlopen
url="https://stackoverflow.com/search?q=html+error+403"
req = Request(url, headers={'User-Agent': 'Mozilla/5.0'})

web_byte = urlopen(req).read()

webpage = web_byte.decode('utf-8')

web_byteเป็นวัตถุไบต์กลับโดยเซิร์ฟเวอร์และชนิดที่นำเสนอเนื้อหาในหน้าเว็บส่วนใหญ่จะเป็นUTF-8 ดังนั้นคุณต้องถอดรหัสweb_byteโดยใช้วิธีถอดรหัส

วิธีนี้ช่วยแก้ปัญหาได้อย่างสมบูรณ์ในขณะที่ฉันพยายามคัดลอกจากเว็บไซต์โดยใช้ PyCharm

PS -> ฉันใช้ python 3.4


4

จากคำตอบก่อนหน้านี้

from urllib.request import Request, urlopen       
#specify url
url = 'https://xyz/xyz'
req = Request(url, headers={'User-Agent': 'XYZ/3.0'})
response = urlopen(req, timeout=20).read()

สิ่งนี้ได้ผลสำหรับฉันโดยการขยายระยะหมดเวลา


2

เนื่องจากหน้าเว็บทำงานในเบราว์เซอร์ไม่ใช่เมื่อเรียกภายในโปรแกรม python ดูเหมือนว่าเว็บแอปที่ให้บริการurlนั้นนั้นจะรับรู้ว่าคุณไม่ได้ร้องขอเนื้อหาจากเบราว์เซอร์

สาธิต:

curl --dump-header r.txt http://www.cmegroup.com/trading/products/#sortField=oi&sortAsc=false&venues=3&page=1&cleared=1&group=1

...
<HTML><HEAD>
<TITLE>Access Denied</TITLE>
</HEAD><BODY>
<H1>Access Denied</H1>
You don't have permission to access ...
</HTML>

และเนื้อหาใน r.txt มีบรรทัดสถานะ:

HTTP/1.1 403 Forbidden

ลองโพสต์ส่วนหัว 'User-Agent' ซึ่งปลอมเป็นเว็บไคลเอ็นต์

หมายเหตุ:หน้านี้มีการเรียก Ajax ที่สร้างตารางที่คุณอาจต้องการแยกวิเคราะห์ คุณจะต้องตรวจสอบตรรกะ javascript ของหน้าหรือเพียงแค่ใช้โปรแกรมดีบั๊กของเบราว์เซอร์ (เช่นแท็บ Firebug / Net) เพื่อดูว่าคุณต้องเรียกใช้ URL ใดเพื่อรับเนื้อหาของตาราง


2

จากคำตอบก่อนหน้านี้ได้ผลสำหรับฉันกับ Python 3.7

from urllib.request import Request, urlopen

req = Request('Url_Link', headers={'User-Agent': 'XYZ/3.0'})
webpage = urlopen(req, timeout=10).read()

print(webpage)

1

คุณสามารถลองได้สองวิธี รายละเอียดอยู่ในลิงค์นี้

1) ผ่าน pip

pip install - อัพเกรดใบรับรอง

2) หากไม่ได้ผลให้ลองเรียกใช้Cerificates.commandที่มาพร้อมกับ Python 3 * สำหรับ Mac: (ไปที่ตำแหน่งการติดตั้ง python ของคุณและดับเบิลคลิกที่ไฟล์)

เปิด / Applications / Python \ 3. * / Install \ Certificates.command


1

หากคุณรู้สึกผิดที่แกล้ง user-agent เป็น Mozilla (แสดงความคิดเห็นในคำตอบยอดนิยมจาก Stefano) ก็สามารถทำงานร่วมกับ User-Agent ที่ไม่ใช่ urllib ได้เช่นกัน สิ่งนี้ใช้ได้กับไซต์ที่ฉันอ้างอิง:

    req = urlrequest.Request(link, headers={'User-Agent': 'XYZ/3.0'})
    urlrequest.urlopen(req, timeout=10).read()

แอปพลิเคชันของฉันคือการทดสอบความถูกต้องโดยการคัดลอกลิงก์เฉพาะที่ฉันอ้างถึงในบทความของฉัน ไม่ใช่มีดโกนทั่วไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.