博主刚刚学习Python爬虫没多久,大概对requests库、BeautifulSoup库有所了解,准备找个网站练练手,于是就选了OJ。
首先是使用requests库获得网页的html文本,这都是有各种框架了,就不再赘述。
def getHTML(url):
try:
head={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'}
r = requests.get(url,headers=head)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ''
然后就是使用BeautifulSoup解析html网页,接着需要提取我们需要的信息,网页显示如下:
然后查看网页源代码,可以发现所有这些状态都包含在tbody标签里,而每条状态都是包含在tr标签里,
<tbody>
<tr>
<td><a href="/OnlineJudge/status?owner=&problem=&language=&verdict=&top=445095">445095</a></td>
<td>516030910365 吴薄鸿</td>
<td>
<a href="/OnlineJudge/problem/4012">4012</a>
</td>
<td>
<span class="recordMemoryLimitExceeded">超过内存限制</span>
</td>
<td>0ms</td>
<td>0kb</td>
<td>C++</td>
<td>2017-11-02 13:04:05</td>
</tr>
<tr>
<td><a href="/OnlineJudge/status?owner=&problem=&language=&verdict=&top=445094">445094</a></td>
<td>517021911076 李晓妍</td>
<td>
<a href="/OnlineJudge/problem/4058">4058</a>
</td>
<td>
<span class="recordAccepted">正确</span>
</td>
<td>4ms</td>
<td>5316kb</td>
<td>C++</td>
<td>2017-11-02 13:03:07</td>
</tr>
所以可以使用一个列表来将这些状态存储,同时由于提取是从上往下提取,所以列表前面的是最新的,后面是较早的,为了输出方便,可以将列表倒序以下。
def getList(url):
html=getHTML(url)
soup=BeautifulSoup(html,'html.parser')
urlList=[]
for obj in soup.tbody.findAll('tr'):
urlList.append(obj)
urlList.reverse()
return urlList
再然后就是遍历列表中的每一个对象,再对每一个对象进行一些处理,写入文件中。
def writeList(urlList,startIndex=0):
f=open('scrapy.txt','a')
t=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
f.write('Run Time: '+t+'\n')
if startIndex==len(urlList)-1:
return 0
for i in range(startIndex+1,len(urlList)):
for obj in urlList[i]:
if obj=='\n':
pass
elif obj.string!=None:
f.write(obj.string+'\t')
elif obj.a!=None:
f.write(obj.a.string+'\t')
elif obj.span!=None:
f.write(obj.span.string+'\t')
f.write('\n')
f.close()
我希望每当页面上有新的状态出现时,可以继续写入文件,所以每隔一段时间爬取一下网页,然后从刚爬取的newlist中选取oldlist中没有的写入文件即可。主要方法是返回oldlist最后一个元素在newlist中的位置,然后从那个位置开始写入。
def getLastedNo(urlList):
return urlList[-1].td.string
def getFirstIndex(urlList,no):
for i in range(len(urlList)):
if urlList[i].td.string==no:
return i
最后就是将这些模块整合起来,每隔一段时间爬取一次,将新的写入文件即可。
url='https://acm.sjtu.edu.cn/OnlineJudge/status'
oldList=getList(url)
f=open('scrapy.txt','a')
f.write('=================================\n')
f.close()
writeList(oldList,0)
i=0
print (i)
while True:
time.sleep(200)
newList=getList(url)
start=getFirstIndex(newList,getLastedNo(oldList))
writeList(newList,start)
oldList=newList
i+=1
print (i)
爬取结果如下:
最后,这个程序还有很多Bug,还需要慢慢改进。