2014-10-21 98 views
10

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

但是,在上面的网站上有多个页面可用,我希望这些页面能够被抓取。

例如,通过上面的网址,当我点击“第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') 
+0

这是不是要求或真正poosible任何其他去取HTML东西的工具,如果你想这样做,你必须去与像硒或webdriver的网络驱动器,但它的方式更加复杂,要求。 。祝你好运 – brunsgaard 2014-10-21 23:03:30

+0

这真的只是简单的URL操作。只需使用Google Chrome的检测工具或Firefox的Firebug检查“POST”请求即可。请参阅下面的答案。 – Manhattan 2014-10-21 23:05:28

+0

@Nanashi,你也许应该解释一下如何在你的回答中做你的建议 – 2014-10-21 23:06:51

回答

36

这里的窍门是检查在进出换页动作来的请求时您点击链接查看的其他页面。检查的方法是使用Chrome的检测工具(通过按F12)或在Firefox中安装Firebug扩展。我将在这个答案中使用Chrome的检测工具。请参阅下面的设置。现在

enter image description here

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

enter image description here

点击上面POST方法。它应该弹出一个包含制表符的排序子窗口。点击Headers标签。这个页面列出了请求标题,几乎是另一方(例如站点)需要的标识信息,以便您能够连接(其他人可以比我更好地解释这个问题)。

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

enter image description here

正如你所看到的,查询字符串参数在我们的URL匹配的变量。稍微低一点,你可以看到Form Data下面有pageNum: 2。这是关键。

POST请求通常被称为表单请求,因为这些是您在提交表单,登录到网站等时提出的请求类型。基本上,几乎任何您必须提交信息的地方。大多数人没有看到的是POST请求有一个他们关注的URL。一个很好的例子就是当你登录到一个网站,并且非常简单地看到你的地址栏变成某种乱码网址之后才决定在/index.html或某些地方。

以上段落的基本含义是,您可以(但不总是)将表单数据追加到您的URL中,并且它将执行POST请求。要知道您必须追加的确切字符串,请点击view source

enter image description here

测试,如果它的工作原理是将其添加到URL。

enter image description here

的Et瞧,它的工作原理。现在,真正的挑战是:自动获取最后一页,并抓取所有页面。你的代码非常多。剩下要做的事情就是获取页面的数量,构建一个需要抓取的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] 

enter image description here

希望有所帮助。

编辑:

在百无聊赖中,我想我只是创造了整个类目录的刮刀。而且,当只有一个可用页面时,我更新上面和下面的代码,以便不出错。

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') 
+0

如何确定可用页面的长度或数量? – 2014-10-21 23:12:51

+0

这就是我现在正在做的。 :)等待编辑在jiffy。 – Manhattan 2014-10-21 23:14:33

+0

干杯@Nanashi真的很感谢帮助! – 2014-10-21 23:30:14