使用 BeautifulSoup 和 Python 抓取多个页面
Posted
技术标签:
【中文标题】使用 BeautifulSoup 和 Python 抓取多个页面【英文标题】:Scrape multiple pages with BeautifulSoup and Python 【发布时间】:2014-12-17 07:53:10 【问题描述】:我的代码成功地从 [http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY] 中抓取了 tr align=center 标签并将 td 元素写入文本文件。
但是,我希望能够在上面的网站上抓取多个页面。
例如,对于上面的网址,当我单击“第 2 页”的链接时,整个网址不会改变。我查看了页面源代码,并看到了一个 javascript 代码来前进到下一页。
如何更改我的代码以从所有可用的列出页面中抓取数据?
我的代码仅适用于第 1 页:
import bs4
import requests
response = requests.get('http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY')
soup = bs4.BeautifulSoup(response.text)
soup.prettify()
acct = open("/Users/it/Desktop/accounting.txt", "w")
for tr in soup.find_all('tr', align='center'):
stack = []
for td in tr.findAll('td'):
stack.append(td.text.replace('\n', '').replace('\t', '').strip())
acct.write(", ".join(stack) + '\n')
【问题讨论】:
使用请求或任何其他 go fetch html 东西工具并不是很可行,如果你想这样做,你必须使用像 selenium 或 WebDriver 这样的网络驱动程序,但它更复杂的是请求..祝你好运 这只是简单的 URL 操作,真的。只需使用 Google Chrome 的检查工具或 Firebug for Firefox 检查POST
请求。请参阅下面的答案。
@Nanashi,您也许应该解释如何按照您在回答中的建议进行操作
会的,伙计。只需添加代码即可。 :)
伙计们,顺便说一句,感谢你们保持网络抓取标签的形状! :)
【参考方案1】:
这里的技巧是在您单击链接以查看其他页面时检查进出页面更改操作的请求。检查的方法是使用 Chrome 的检查工具(通过按 F12)或在 Firefox 中安装 Firebug 扩展。我将在这个答案中使用 Chrome 的检查工具。请参阅下面的设置。
现在,我们希望看到的是对另一个页面的 GET
请求或更改页面的 POST
请求。该工具打开时,单击页码。在很短的时间里,只会出现一个请求,它是一个POST
方法。所有其他元素将快速跟随并填满页面。请参阅下文了解我们正在寻找的内容。
点击上面的POST
方法。它应该调出一个带有标签的子窗口。单击Headers
选项卡。此页面列出了请求标头,几乎是对方(例如网站)需要您才能连接的标识信息(其他人可以比我更好地解释这一点)。
只要 URL 包含页码、位置标记或类别等变量,网站通常会使用查询字符串。长话短说,它类似于 SQL 查询(实际上,有时它是一个 SQL 查询),它允许站点提取您需要的信息。如果是这种情况,您可以检查查询字符串参数的请求标头。向下滚动一下,您应该会找到它。
如您所见,查询字符串参数与我们 URL 中的变量匹配。在下面一点,你可以看到Form Data
和pageNum: 2
在它下面。这是关键。
POST
请求通常称为表单请求,因为这些请求是在您提交表单、登录网站等时发出的请求。基本上,几乎所有您必须提交信息的地方。大多数人没有看到的是 POST
请求有一个他们遵循的 URL。这方面的一个很好的例子是,当您登录到一个网站,并且非常简短地看到您的地址栏变成某种乱码的 URL,然后再选择 /index.html
或类似的东西。
上述段落的基本意思是,您可以(但不总是)将表单数据附加到您的 URL,它会在执行时为您执行 POST
请求。要知道您必须附加的确切字符串,请单击view source
。
通过将其添加到 URL 来测试它是否有效。
瞧,它有效。现在,真正的挑战是:自动获取最后一页并抓取所有页面。你的代码就在那里。剩下要做的唯一事情是获取页面数量、构建要抓取的 URL 列表并对其进行迭代。
修改后的代码如下:
from bs4 import BeautifulSoup as bsoup
import requests as rq
import re
base_url = 'http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY'
r = rq.get(base_url)
soup = bsoup(r.text)
# Use regex to isolate only the links of the page numbers, the one you click on.
page_count_links = soup.find_all("a",href=re.compile(r".*javascript:goToPage.*"))
try: # Make sure there are more than one page, otherwise, set to 1.
num_pages = int(page_count_links[-1].get_text())
except IndexError:
num_pages = 1
# Add 1 because Python range.
url_list = ["&pageNum=".format(base_url, str(page)) for page in range(1, num_pages + 1)]
# Open the text file. Use with to save self from grief.
with open("results.txt","wb") as acct:
for url_ in url_list:
print "Processing ...".format(url_)
r_new = rq.get(url_)
soup_new = bsoup(r_new.text)
for tr in soup_new.find_all('tr', align='center'):
stack = []
for td in tr.findAll('td'):
stack.append(td.text.replace('\n', '').replace('\t', '').strip())
acct.write(", ".join(stack) + '\n')
我们使用正则表达式来获取正确的链接。然后使用列表推导,我们构建了一个 URL 字符串列表。最后,我们遍历它们。
结果:
Processing http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY&pageNum=1...
Processing http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY&pageNum=2...
Processing http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY&pageNum=3...
[Finished in 6.8s]
希望对您有所帮助。
编辑:
出于无聊,我想我刚刚为整个班级目录创建了一个刮板。另外,我更新了上面和下面的代码,以便在只有一个页面可用时不会出错。
from bs4 import BeautifulSoup as bsoup
import requests as rq
import re
spring_2015 = "http://my.gwu.edu/mod/pws/subjects.cfm?campId=1&termId=201501"
r = rq.get(spring_2015)
soup = bsoup(r.text)
classes_url_list = [c["href"] for c in soup.find_all("a", href=re.compile(r".*courses.cfm\?campId=1&termId=201501&subjId=.*"))]
print classes_url_list
with open("results.txt","wb") as acct:
for class_url in classes_url_list:
base_url = "http://my.gwu.edu/mod/pws/".format(class_url)
r = rq.get(base_url)
soup = bsoup(r.text)
# Use regex to isolate only the links of the page numbers, the one you click on.
page_count_links = soup.find_all("a",href=re.compile(r".*javascript:goToPage.*"))
try:
num_pages = int(page_count_links[-1].get_text())
except IndexError:
num_pages = 1
# Add 1 because Python range.
url_list = ["&pageNum=".format(base_url, str(page)) for page in range(1, num_pages + 1)]
# Open the text file. Use with to save self from grief.
for url_ in url_list:
print "Processing ...".format(url_)
r_new = rq.get(url_)
soup_new = bsoup(r_new.text)
for tr in soup_new.find_all('tr', align='center'):
stack = []
for td in tr.findAll('td'):
stack.append(td.text.replace('\n', '').replace('\t', '').strip())
acct.write(", ".join(stack) + '\n')
【讨论】:
我可以做些什么来确定可用页面的长度或数量? 干杯 @Nanashi 非常感谢您的帮助! @PhilipMcQuitty:你去吧。我认为这几乎涵盖了有关此刮擦的所有内容。 你超出了我希望从这个问题中得到的答案。 *** 需要更多像你这样的用户,这是一个巨大的帮助。 很高兴为您提供帮助。绝对喜欢刮,所以我尽量在这些标签中提供帮助。享受吧!以上是关于使用 BeautifulSoup 和 Python 抓取多个页面的主要内容,如果未能解决你的问题,请参考以下文章
使用 Python 和 BeautifulSoup(将网页源代码保存到本地文件中)
使用python抓取并分析数据—链家网(requests+BeautifulSoup)(转)
使用 urllib 和 BeautifulSoup 通过 Python 从 Web 检索信息
python 使用BeautifulSoup和Python从网页中提取文本