我们来看看抓取球员数据的详细过程:
首先我们定义了一个get_players方法,该方法会返回某一请求页面上所有球员的数据。为了得到所有的数据,我们通过一个for循环,因为要循环各个联赛,每个联赛又有多个分页,一般情况下是需要一个双重循环的:
2 | for j in range ( 0 , 100 ): |
3 | url = BASE_URL + PLAYER_LIST_QUERY % (l,n) |
Python的list comprehension可以很方便的通过构造一个列表的方式来减少循环的层次。
另外Python还有一个很方便的语法来合并连个列表: list = list1 + list2
好我们再看看如何使用BeautifulSoup来抓取网页中我们需要的内容。
首先调用urlopen读取对应url的内容,通常是一个html,用该html构造一个beautifulsoup对象。
beautifulsoup对象支持很多查找功能,也支持类似css的selector。通常如果有一个DOM对象是<xx class='cc'>,我们使用以下方式来查找:
1 | obj = soup.find( "xx" , "cc" ) |
另外一种常见的方式就是通过CSS的selector方式,在上述代码中,我们选择class=searchResult元素里面,所有的tr元素,过滤掉th也就是表头元素。
1 | for dd in soup.select( '.searchResult tr' ) if dd.contents[ 1 ].name ! = 'th' |
对于每一行记录tr,生成一条球员记录,并存放在一个列表中。所以我们就循环tr的内容tr.contents,获得对应的field内容。
对于每一个tr的content,我们先检查其类型是不是一个Tag,对于Tag类型有几种情况,一种是包含img的情况,我们需要取出球员的头像图片的网址。
另一种是包含了一个链接,指向其他数据内容
所以在代码中要分别处理这些不同的情况。
对于一个Tag对象,Tag.x可以获得他的子对象,Tag['x']可以获得Tag的attribute的值。
所以用item.img['src']可以获得item的子元素img的src属性。
对已包含链接的情况,我们通过urlparse来获取查询url中的参数。这里我们利用了dict comprehension的把查询参数放入一个dict中,然后添加到列表中。 1 | dict ([(k,v[ 0 ]) for k,v in urlparse.parse_qs(o).items()]) |
对于其它情况,我们使用Python 的and or表达式以确保当Tag的内容为空时,我们写入‘na’,该表达式类似C/C++或Java中的三元操作符 X ? A : B
然后有一段代码判断当前记录的长度是否大于10,不大于10则用空值填充,目的是避免一些不一致的地方。 2 | for i in range ( 0 , 10 - len (record)): |
最后,我们把query中的一些相关的参数如球员的id,球队的id,所在的联赛代码等加入到列表。 1 | record.append( unicode (link, 'utf-8' )) |
2 | record.append( unicode (query[ "id" ], 'utf-8' )) |
3 | record.append( unicode (query[ "teamid" ], 'utf-8' )) |
4 | record.append( unicode (query[ "lega" ], 'utf-8' )) |
最后我们把本页面所有球员的列表放入一个列表返回。
好了,现在我们拥有了一个包含所有球员的信息的列表,我们需要把它存下来,以进一步的处理,分析。通常,csv格式是一个常见的选择。
02 | def write_csv(filename, content, header = None ): |
03 | file = open (filename, "wb" ) |
04 | file .write( '\xEF\xBB\xBF' ) |
05 | writer = csv.writer( file , delimiter = ',' ) |
07 | writer.writerow(header) |
09 | encoderow = [dd.encode( 'utf8' ) for dd in row] |
10 | writer.writerow(encoderow) |
12 | write_csv( 'players.csv' ,result,player_fields) |
这里需要注意的就是关于encode的问题。因为我们使用的时utf-8的编码方式,在csv的文件头,需要写入\xEF\xBB\xBF,详见这篇文章
好了现在大功告成,抓取的csv如下图:
|