使用BeautifulSoup和Python抓取多个页面

Phi*_*tty 13 html python page-numbering web-scraping

我的代码成功地从[ http://my.gwu.edu/mod/pws/courses.cfm?campId=1&termId=201501&subjId=ACCY ]中删除了tr align = center标签,并将td元素写入文本文件.

但是,上面的网站上有多个页面,我希望能够抓取这些页面.

例如,使用上面的url,当我点击"第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')
Run Code Online (Sandbox Code Playgroud)

Jer*_*ino 43

这里的技巧是当您单击链接以查看其他页面时,检查进出页面更改操作的请求.检查这一点的方法是使用Chrome的检查工具(通过按下F12)或在Firefox中安装Firebug扩展.我会在这个答案中使用Chrome的检测工具.请参阅下面的我的设置.

在此输入图像描述

现在,我们想要看到的是GET对另一个页面的POST请求或更改页面的请求.工具打开时,单击页码.在一个非常短暂的时刻,只会出现一个请求,这是一种POST方法.所有其他元素将快速跟随并填充页面.请参阅下文,了解我们正在寻找的内容.

在此输入图像描述

单击上面的POST方法.它应该打开一个包含选项卡的子窗口.单击Headers选项卡.这个页面列出了请求标题,几乎是另一方(例如网站)需要你能够连接的标识内容(其他人可以比我更好地解释这个问题).

每当URL包含页码,位置标记或类别等变量时,通常不会使用查询字符串.长话短说,它类似于SQL查询(实际上,它有时是一个SQL查询),允许网站提取您需要的信息.如果是这种情况,您可以检查查询字符串参数的请求标头.向下滚动一下你应该找到它.

在此输入图像描述

如您所见,查询字符串参数与URL中的变量匹配.稍微低一点,你可以看到Form DatapageNum: 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')
Run Code Online (Sandbox Code Playgroud)

我们使用正则表达式来获取正确的链接.然后使用列表推导,我们构建了一个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]
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

希望有所帮助.

编辑:

出于纯粹的无聊,我想我刚刚为整个类目录创建了一个刮刀.此外,我更新上面和下面的代码,以便在只有一个页面可用时不会出错.

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')
Run Code Online (Sandbox Code Playgroud)

  • 你超越了我希望从这个问题中得到的东西。Stackoverflow 需要更多像您这样的用户,这是一个巨大的帮助。 (5认同)