直接入正题,写一个 python 爬虫,最重要的其实是找到入口,从哪里开始爬,以 tumblr 为例,只要能够获取到用户列表,通过每个用户的主页就能拿到每个用户发的或者转发的视频,原作者的名字也可以拿到。
代码如下:
def download(self, url):
# 用 requests 库获取 url 的网页内容
res = requests.get(url)
# 用 bs4 解析 html
soup = BeautifulSoup(res.text)
# 获取 iframe 标签列表
iframes = soup.find_all('iframe')
tmp_source = []
for i in iframes:
# 获取视频地址
source = i.get('src', '').strip()
# 过滤内容
if source and source.find('https://www.tumblr.com/video') != -1 and source not in self.total_url:
tmp_source.append(source)
print u'新增链接:' + source
tmp_user = []
# 获取用户列表
new_users = soup.find_all(class_='reblog-link')
for user in new_users:
username = user.text.strip()
# 过滤用户
if username and username not in self.total_user:
# 将用户放入待爬取队列
self.user_queue.put(username)
# 加入总用户列表中
self.total_user.append(username)
tmp_user.append(username)
print u'新增用户:' + username
为了提高爬虫的性能,可以采用多线程的方式,代码如下
class Tumblr(threading.Thread):
def run(self):
# 为了能处理多线程 ctr+c 的信号问题,具体见完整代码
global is_exit
while not is_exit:
user = self.user_queue.get()
url = 'http://%s.tumblr.com/' % user
self.download(url)
time.sleep(2)
def main():
# 线程数
NUM_WORKERS = 10
# 待爬取队列
queue = Queue.Queue()
# 开始的时候将一个热门博主的 username 加入到待爬取队列
queue.put('username')
for i in range(NUM_WORKERS):
# 实例化线程对象
tumblr = Tumblr(queue)
# 设置线程为守护线程
tumblr.setDaemon(True)
tumblr.start()
最后将用户和视频资源写入到文件中
# 由于多线程写文件会出现线程安全问题,所以加了个线程锁
mutex.acquire()
if tmp_user:
self.f_user.write('\n'.join(tmp_user)+'\n')
if tmp_source:
self.f_source.write('\n'.join(tmp_source)+'\n')
# 释放锁
mutex.release()
这样一个多线程 python 爬虫就基本完成了,完整代码见 [github](https://github.com/facert/tumblr_spider)
最后声明这是一个正经的爬虫(严肃脸),爬取的资源跟你第一个填入的 username 有很大关系,老司机怎么开车我不管 ╭(╯^╰)╮