动态网页数据挖掘一例

来源:互联网 发布:mac 命令行查找文件夹 编辑:程序博客网 时间:2024/06/06 04:34

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

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


#coding:utf8from bs4 import BeautifulSoup as spimport urllib2import pandas as pdfrom pandas import DataFrame as dfimport osimport reimport timefrom selenium import webdriverdef 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" onclick="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)




0 0
原创粉丝点击