这次的网址是:中国土地市场网
我需要这个网站里面每个链接点开之后的信息,并将这些信息整合到一个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
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
当断点出现需要重新开始时,载入之前的工作,
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
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)