动态网页数据挖掘一例

这次的网址是:中国土地市场网

我需要这个网站里面每个链接点开之后的信息,并将这些信息整合到一个csv文件中。网页一共有200页,每页30条记录,共计6000条记录。


#coding:utf8
from bs4 import BeautifulSoup as sp
import urllib2
import pandas as pd
from pandas import DataFrame as df
import os
import re
import time

from selenium import webdriver

def alpha(x):
    return filter(str.isalpha,x)
def num(x):
    return filter(str.isdigit,x)

我们以第一条记录点开后的网址为例: 第一条记录,确定存放最终结果的DataFrame如下:

cols=['宗地标识:','宗地编号:','所在行政区:','宗地座落:','土地面积:','土地他项权利人证号:','土地使用权证号:','土地抵押人名称:','土地抵押人性质:','土地抵押权人:','抵押土地用途:','抵押土地权属性质与使用权类型:','抵押面积(公顷):','评估金额(万元):','抵押金额(万元):','土地抵押登记起始时间:','土地抵押登记结束时间:']
a=df(columns=cols,index=range(30))

因为数据均为中文,所以记得要在程序开头加上utf8编码,不然会乱码(其实乱码也没有关系,存入csv文件里面之后改一下编码格式依然是可读的)


首先,我们先来写一个函数,这个函数会将一个具体链接的网址中数据抓出来,并写入一个DataFrame中去。因为每条记录所在的网址打开后比较简单,是一个静态的html,没什么多说的:

def SingleRecord(trs,count,daf):
    ''' Return the dataframe after a new record is detected
                           这里的trs代表着html网页里面的tr元素的合集,由main函数传入,daf就是目标DataFrame,count是记录的条数,从0到5999
    '''
    tmp=[]
    for cnt,tr in enumerate(trs):
        rec=tr.text.split('\n')
        if cnt==0:
            pass
        if cnt==1:
            tmp.append(rec[2])
            tmp.append(rec[4])
        if cnt==2:
            tmp.append(rec[3])
        if cnt>2:
            tmp.append(rec[2])
            tmp.append(rec[4])
    daf.ix[count%30]=tmp
    if (count+1)%30==0:
        daf.to_csv(r"C:\Users\turmoil\Desktop\fuck\%s.csv"%(str((count+1)/30)),encoding='utf8')
        daf=df(columns=cols,index=range(30))
    return daf


接下来,我们需要做的是事情是对于每一页列表,我们要找到其中的30条记录的具体地址,这个直接从源代码中可以用beautifulsoup解析出来,如下所示:

def PageUrls(html):
    ''' get the effective urls in a page, it will return a list,此处的html即为包含30条记录地址的网页源码
    '''
    pat = re.compile(r'href="([^"]*)"') #过滤出里面存在的记录链接   
    base="http://www.landchina.com/"
    soup=sp(html)
    table=soup.find('table',id="TAB_contentTable")
    trs=table.findAll('tr')
    result=[]
    for tr in trs:
        h=pat.search(str(tr))
        if h:    
            href=h.group(1)
            result.append(base+href.replace(";","&"))
    return result

现在,我们可以根据记录的合集网页来获取每一条记录的具体地址了,并且可以通过地址来获取每一条记录。主要的事情看上去做完了,其实并没有。我们还需要遍历第1页到第200页中的所有页数,这个会比较麻烦,因为网页是动态的,所以需要处理一下JavaScript。从当前页跳到下一页时,需要点击页面上的“下页”
cur_page=1    
for i in range(cur_page,200):    
    browser.find_element_by_link_text("下页").click()
    cont=browser.page_source


到了这里,基本工作差不多都完成了,但是由于网页或者别的问题,在抓取过程中会经常遇到各种各样的错误。这个时候从断点处继续工作会比较重要,而发生断点的时候可能会在比较后面的页数,例如150页。如果用selenium模拟点“下页”来完成这个动作,需要点100多次,非常不方便。这个时候可以调用selenium的JavaScript处理方法来直接跳转到第150页,具体如下:

browser=webdriver.Chrome()
loc="http://www.landchina.com/default.aspx?tabid=351"
browser.get(loc)
go=browser.find_element_by_xpath("//input[@type='button']") 
browser.execute_script("QueryAction.GoPage('TAB',123,200)", go) # go按钮的JS代码是在网页的源码中分析出来的,在点击go这个按钮的时候,里面其实是传入了一个JS函数<input type="button" value="go" οnclick="QueryAction.GoPage('TAB',this.previousSibling.value,200)"/>,因此可以模拟直接执行这个函数来进行页面跳转
content=browser.page_source


这个时候,再对上面跳转后的源代码应用PageUrls函数,即可在断点处继续开始,而不用从第一页开始了。
当断点出现需要重新开始时,载入之前的工作,

def reload(url):
    file_list=os.listdir(r"C:\Users\turmoil\Desktop\fuck")
    if file_list==[]:
        end=1
    else:
        file_list=[int(num(x)) for x in file_list]
    end=max(file_list)+1
    cycle=(end-1)/10
    browser=webdriver.Chrome()
    browser.get(url)
    print end-1,cycle
    if cycle==0:
        return browser,end
    
    for i in range(cycle):
        try:
            browser.find_elements_by_link_text("...")[-1].click()
        except:
            time.sleep(5)
            browser.refresh()
            browser.find_elements_by_link_text("...")[-1].click()
#         time.sleep(5)
    if str(end)[-1]!='1':
        browser.find_element_by_link_text(str(end)).click()
    return browser,end


这样,基本上元素都齐了,下面就是把这些合在一起的main函数啦:

def main(url,daf):
    browser,end=reload(url)
    content=browser.page_source
    urls=PageUrls(content)
    
    t=webdriver.Chrome()
    cur_page=end
    
    for k,web in enumerate(urls):
        t.get(web)
        html=t.page_source
        soup=sp(html)
        table=soup.find('table',id="FormView21_1")
        if table==None:
            time.sleep(8)
            t.refresh()
            html=t.page_source
            soup=sp(html)
            table=soup.find('table',id="FormView21_1")

        trs=table.findAll('tr')
        daf=SingleRecord(trs,k+(cur_page-1)*30,daf)
    
    for i in range(cur_page+1,201):    
        browser.find_element_by_link_text("下页").click()
        cont=browser.page_source
        try:
            ur=PageUrls(cont)
        except AttributeError:
            time.sleep(20)
            browser.refresh()
            time.sleep(8)
            browser.refresh()
            cont=browser.page_source
            ur=PageUrls(cont)
            
        cur_page=cur_page+1
        
        for j,w in enumerate(ur):
            t.get(w)
            html=t.page_source
            soup=sp(html)
            table=soup.find('table',id="FormView21_1")
            if table==None:
                time.sleep(20)
                t.refresh()
                time.sleep(8)
                t.refresh()
#                 t.get(w)
                html=t.page_source
                soup=sp(html)
                table=soup.find('table',id="FormView21_1")
                trs=table.findAll('tr')
                daf=SingleRecord(trs,(i-1)*30+j,daf)
                print (i-1)*30+j          
            else:
                trs=table.findAll('tr')
                daf=SingleRecord(trs,(i-1)*30+j,daf)
    browser.quit()
    t.quit()


其实这里面对网页出错的处理并不好,因为只是重新加载了一次。实际运行过程中可能需要加载多次。这个时候判断情况需要更改一下,用While循环做判断的话效率会更高。

if __name__=="__main__":
    url="http://www.landchina.com/default.aspx?tabid=351"
    main(url,a)




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值