繁体   English   中英

使用 BeautifulSoup 使用不变的 URL 抓取多个页面

[英]Scraping multiple pages with an unchanging URL using BeautifulSoup

我正在使用Beautiful Soup从非英语网站中提取数据。 现在我的代码只从关键字搜索中提取前十个结果。 该网站旨在通过“更多”按钮访问其他结果(有点像无限滚动,但您必须继续单击更多才能获得下一组结果)。 当我单击“更多”时,URL 不会改变,所以我不能每次都迭代不同的 URL。

我真的很想在两件事上得到一些帮助。

  1. 修改下面的代码,以便我可以从所有页面获取数据,而不仅仅是前 10 个结果
  2. 插入一个计时器 function 以便服务器不会阻止我

我正在添加一张“更多”按钮的照片,因为它不是英文的。 它在页面末尾以蓝色文本显示。 在此处输入图像描述

import requests, csv, os
from bs4 import BeautifulSoup
from time import strftime, sleep

# make a GET request (requests.get("URL")) and store the response in a response object (req)
responsePA = requests.get('https://www.prothomalo.com/search?q=%E0%A6%A7%E0%A6%B0%E0%A7%8D%E0%A6%B7%E0%A6%A3')

# read the content of the server’s response
rawPagePA = responsePA.text

soupPA = BeautifulSoup(rawPagePA)
# take a look
print (soupPA.prettify())

urlsPA = [] #creating empty list to store URLs
for item in soupPA.find_all("div", class_= "customStoryCard9-m__story-data__2qgWb"): #first part of loop selects all items with class=field-title
    aTag = item.find("a") #extracting elements containing 'a' tags
    urlsPA.append(aTag.attrs["href"]) 

print(urlsPA) 

#Below I'm getting the data from each of the urls and storing them in a list
PAlist=[]
for link in urlsPA:
    specificpagePA=requests.get(link) #making a get request and stores the response in an object
    rawAddPagePA=specificpagePA.text # read the content of the server’s response
    PASoup2=BeautifulSoup(rawAddPagePA) # parse the response into an HTML tree
    PAcontent=PASoup2.find_all(class_=["story-element story-element-text", "time-social-share-wrapper storyPageMetaData-m__time-social-share-wrapper__2-RAX", "headline headline-type-9 story-headline bn-story-headline headline-m__headline__3vaq9 headline-m__headline-type-9__3gT8S", "contributor-name contributor-m__contributor-name__1-593"]) 
    #print(PAcontent)
    PAlist.append(PAcontent)

您实际上并不需要 Selenium。


按钮发送以下 GET 请求:

https://www.prothomalo.com/api/v1/advanced-search?fields=headline,subheadline,slug,url,hero-image-s3-key,hero-image-caption,hero-image-metadata,first-published-at,last-published-at,alternative,published-at,authors,author-name,author-id,sections,story-template,metadata,tags,cards&offset=10&limit=6&q=ধর্ষণ

重要的部分是末尾的“ offset=10&limit=6 ”,随后单击按钮只会将该偏移量增加 6。

得到

所有页面的数据

行不通,因为似乎有很多而且我看不到确定有多少的选项。 因此,您最好选择一个数字并请求,直到您拥有那么多链接。

由于此请求返回 JSON,因此您最好只解析它,而不是将 HTML 提供给 BeautifulSoup。


看看那个:

import requests
import json

s = requests.Session()
term = 'ধর্ষণ'
count = 20

# Make GET-Request
r = s.get(
    'https://www.prothomalo.com/api/v1/advanced-search',
    params={
        'offset': 0,
        'limit': count,
        'q': term
    }
)

# Read response text (a JSON file)
info = json.loads(r.text)

# Loop over items
urls = [item['url'] for item in info['items']]

print(urls)

这将返回以下列表:

['https://www.prothomalo.com/world/asia/পাকিস্তানে-সন্তানদের-সামনে-মাকে-ধর্ষণের-মামলায়-দুজনের-মৃত্যুদণ্ড', 'https://www.prothomalo.com/bangladesh/district/খাবার-দেওয়ার-কথা-বদলে-ধর্ষণ-অবসরপ্রাপ্ত-শিক্ষকের-বিরুদ্ধে-মামলা', 'https://www.prothomalo.com/bangladesh/district/জয়পুরহাটে-অপহরণ-ও-ধর্ষণ-মামলায়-যুবকের-যাবজ্জীবন-কারাদণ্ড', 'https://www.prothomalo.com/bangladesh/district/কিশোরীকে-ধর্ষণ-মামলায়-যুবক-গ্রেপ্তার', 'https://www.prothomalo.com/bangladesh/সুবর্ণচরে-এত-ধর্ষণ-কেন', 'https://www.prothomalo.com/bangladesh/district/১২-বছরের-ছেলেকে-ধর্ষণ-মামলায়-একজন-গ্রেপ্তার', 'https://www.prothomalo.com/bangladesh/district/ভালো-পাত্রের-সঙ্গে-বিয়ে-দেওয়ার-কথা-বলে-কিশোরীকে-ধর্ষণ-গ্রেপ্তার-১', 'https://www.prothomalo.com/bangladesh/district/সখীপুরে-দুই-শিশুকে-ধর্ষণ-মামলার-আসামিকে-গ্রেপ্তারের-দাবিতে-মানববন্ধন', 'https://www.prothomalo.com/bangladesh/district/বগুড়ায়-ছাত্রী-ধর্ষণ-মামলায়-তুফান-সরকারের-জামিন-বাতিল', 'https://www.prothomalo.com/world/india/ধর্ষণ-নিয়ে-মন্তব্যের-জের-ভারতের-প্রধান-বিচারপতির-পদত্যাগ-দাবি', 'https://www.prothomalo.com/bangladesh/district/ফুলগাজীতে-ধর্ষণ-মামলায়-অভিযুক্ত-ইউপি-চেয়ারম্যান-বরখাস্ত', 'https://www.prothomalo.com/bangladesh/district/ধুনটে-ধর্ষণ-মামলায়-ছাত্রলীগ-নেতা-গ্রেপ্তার', 'https://www.prothomalo.com/bangladesh/district/নোয়াখালীতে-কিশোরীকে-ধর্ষণ-ভিডিও-ধারণ-ও-অপহরণের-অভিযোগে-গ্রেপ্তার-২', 'https://www.prothomalo.com/bangladesh/district/বাবার-সঙ্গে-দেখা-করানোর-কথা-বলে-স্কুলছাত্রীকে-ধর্ষণ', 'https://www.prothomalo.com/opinion/column/ধর্ষণ-ঠেকাতে-প্রযুক্তির-ব্যবহার', 'https://www.prothomalo.com/world/asia/পার্লামেন্টের-মধ্যে-ধর্ষণ-প্রধানমন্ত্রীর-ক্ষমা-প্রার্থনা', 'https://www.prothomalo.com/bangladesh/district/তাবিজ-দেওয়ার-কথা-বলে-গৃহবধূকে-ধর্ষণ-কবিরাজ-আটক', 'https://www.prothomalo.com/bangladesh/district/আদালত-প্রাঙ্গণে-বিয়ে-করে-জামিন-পেলেন-ধর্ষণ-মামলার-আসামি', 'https://www.prothomalo.com/bangladesh/district/কিশোরীকে-দল-বেঁধে-ধর্ষণ-ও-ভিডিও-ধারণ-গ্রেপ্তার-৩', 'https://www.prothomalo.com/bangladesh/district/ধর্ষণ-মামলায়-সহকারী-স্টেশনমাস্টার-গ্রেপ্তার']

通过调整计数,您可以设置要检索的 url(文章)的数量, term是 search-term。

requests.Session对象用于具有一致的 cookies。


如果您有任何问题随时问。


编辑:

  1. 以防您想知道我是如何通过单击按钮发现发送了哪个GET请求:我从浏览器 (Firefox) 的开发人员工具转到网络分析- 选项卡,单击按钮,观察正在发送的请求发送并复制了 URL:

    从网络分析选项卡发送的请求

  2. .get函数中对params参数的另一种解释:它包含(以 python-dictionary-format 格式)通常会在问号后附加到 URL 的所有参数。 所以

    requests.get('https://www.prothomalo.com/search?q=%E0%A6%A7%E0%A6%B0%E0%A7%8D%E0%A6%B7%E0%A6%A3')

    可以写成

    requests.get('https://www.prothomalo.com/search', params={'q': 'ধর্ষণ'})

    这使它看起来更好看,您实际上可以看到您正在搜索的内容,因为它是用 unicode 编写的,并且尚未为 URL 编码。


编辑
如果脚本开始返回一个空的 JSON 文件,因此没有 URL,您可能必须像这样设置一个用户代理(我使用的是 Firefox,但任何浏览器都应该没问题):

s.headers.update({
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:87.0) '
                  'Gecko/20100101 Firefox/87.0'
})

只需将该代码放在初始化会话对象的行下方( s =...行)。
用户代理告诉站点什么样的程序正在访问他们的数据。

永远记住,服务器还有其他事情要做,网页还有其他优先级,而不是向一个人发送数千个搜索结果,所以尽量保持流量尽可能低。 抓取 5000 个 URL 很多,如果你真的必须多次这样做,请在发出下一个请求之前在任何地方放置至少几秒钟的sleep(...) (不仅仅是为了防止被阻止,而是为了对向您提供您要求的信息的人很好)。
你把 sleep 放在哪里并不重要,因为你真正与服务器联系的唯一时间是s.get(...)行。

这是您在 bs4 中添加 selenium 的地方。 要添加要加载的站点的点击,然后获取页面内容。

您可以从链接下载 geckodriver

模拟代码将如下所示,

from bs4 import BeautifulSoup
from selenium import webdriver

url = "https://www.prothomalo.com/search?q=%E0%A6%A7%E0%A6%B0%E0%A7%8D%E0%A6%B7%E0%A6%A3"

driver = webdriver.Firefox(executable_path=r'geckodriver.exe')
driver.get(url)

# You need to iterate over this with a loop on how many times you want to click more, 
#do remember if it takes time to fetch the data try adding time.sleep() to wait for the page to load
driver.find_element_by_css_selector('{class-name}').click()

# Then you just get the page content 
soup = BeautifulSoup(driver.page_source, 'html')

# now you have the content loaded with beautifulsoap and can manipulate it as you were doing previously
{YOUR CODE}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM