5/04/2015

Lấy hình từ Flickr với JavaScript


Cách đây vài hôm, ông anh họ gặp tôi và nhờ giúp ổng một chuyện gấp. Số là thế này, ổng tìm được một tài khoản Flickr chứa đầy những tấm hình ổng thích (xin đừng hỏi tôi là hình gì nhé). Ổng muốn tải toàn bộ hình từ tài khoản đó về máy. Tuy nhiên, tài khoản đó có hơn 10,000 tấm, tải về theo cách thủ công, mở từng tấm lên rồi tải thì phải mất cả năm trời mới xong hết đống hình đó. Do vậy, ổng tìm đến tôi để nhờ giúp đỡ. Sau khoảng một giờ mày mò trong cái API Documentation của Flickr, tôi cũng đã tìm ra được cách để chôm toàn bộ link hình từ một tài khoản Flickr bất kỳ. Đặc biệt, toàn bộ ứng dụng tải hình Flickr này chỉ dùng JavaScript.

Lấy API Key từ Flickr

Trước khi viết ứng dụng này, ta phải lấy API Key từ Flickr. Đây là một chuỗi các ký tự giúp Flickr quản lý việc sử dụng API của người dùng. Để lấy API Key, ta đăng nhập vào Flickr, sau đó, vào menu Explore rồi chọn App Garden. Phía bên phải, ta sẽ thấy mục Get an API Key, và trong trang tiếp theo, ta sẽ chọn phần Non-Commercial Key để lấy key dùng cho mục đích phi thương mại. Cuối cùng, Flickr sẽ cung cấp cho ta một cái key để dùng cho ứng dụng của mình. Lưu ý rằng đây là chìa khóa để truy cập vào dịch vụ API của Flickr, bất kỳ ai có key này cũng đều có thể sử dụng API từ tài khoản của bạn. Do đó, ta phải luôn giữ kín cái key này.

Tạo trang HTML

Tiếp theo, ta sẽ tiến hành tạo trang HTML. Trang này chứa một form rất đơn giản, chỉ bao gồm một textbox để nhập vào số ID tài khoản Flickr và một nút bấm để gửi request. Ta cũng có thể thêm nhiều thành phần khác cũng như CSS để định kiểu, tuy nhiên, bấy nhiêu đây là đủ để minh họa cho ứng dụng này rồi. Nếu bạn muốn sáng tạo thêm thì cứ việc. Sau đây là toàn bộ code trong thẻ <body> của trang HTML:
Bây giờ ta sẽ chuyển qua phần quan trọng nhất của chương trình: viết code JavaScript cho ứng dụng.

Viết code JavaScript

Đầu tiên, ta cần thêm thư viện jQuery vào trang HTML trước thẻ đóng </body>. Thay vì viết mọi thứ từ đầu, tôi sẽ tận dụng hàm gửi Ajax request và xử lý JSON của jQuery. Kế đến, tôi tạo một file .js mới có tên script vào cũng nhúng vào trang HTML bên dưới phần chèn thư viện jQuery.
Tiếp theo, tôi sẽ lần lượt khai báo các biến tham số cần thiết để dùng trong việc gửi request lên server Flickr. Ta có thể tham khảo chi tiết về những tham số này trongDocumentation.
Chức năng của các biến như sau:
  • Dòng 1 chính là đường link để truy cập vào dịch vụ API của Flickr.
  • Dòng 2 là API Key mà Flickr cung cấp cho ta khi đăng ký lúc nãy.
  • Dòng 3 xác định số lượng hình trong một trang. Với mỗi request thì ta chỉ được lấy tối đa 500 hình.
  • Dòng 4 là biến theo dõi trang hiện tại. Từ đó, ta có thể đến trang tiếp theo bằng cách tăng biến này lên.
  • Dòng 5 khai báo biến totalPhotos để lưu trữ tổng số lượng hình mà tài khoản có.
  • Dòng 6 cũng tương tự như dòng 5, giúp lưu lại tổng số trang hiện có.
  • Dòng 7 là những tham số phụ nhằm cung cấp cho Flickr biết kích thước hình mà ta muốn lấy. Ở đây tôi muốn lấy tất cả các kích thước hiện có của tấm hình, từ kích cỡ trung bình (medium) cho đến lớn nhất (original). Thông thường, khi tải hình, ta chỉ muốn download ảnh có kích cỡ lớn nhất. Tuy nhiên, có những trường hợp một tấm ảnh không có đầy đủ các kích thước mà ta muốn. Vì vậy, tôi lấy về toàn bộ kích thước để kiểm tra từ từ, nếu kích thước lớn nhất không tồn tại, tôi sẽ lấy kích thức lớn thứ 2, nếu cũng không có thì tôi sẽ lấy kích thước lớn kế tiếp, và cứ như thế cho đến kích thước trung bình.
  • Dòng 8 tôi khai báo biến để chứa toàn bộ các tham số. Thực ra, ta không cần biến này nhưng tôi muốn mọi thứ rõ ràng và gọn gàng hơn.
  • Dòng 9, tôi khai báo biến interval. Lý do tại sao tôi lại tạo biến này sẽ được giải thích sau.
Kế tiếp, tôi sẽ tiến hành viết các hàm cần thiết để phục vụ cho mục đích lấy hình. Hàm đầu tiên ta cần viết là hàm getUserPhotos(). Nghe tên chắc ai cũng có thể đoán ra mục đích chính của hàm này là gì rồi.
Trong hàm này, tôi sẽ gán một object vào trong biến reqParams, và sau đó sẽ truyền nó vào hàm getJSON của jQuery ở dòng 13. Các thuộc tính trong đối tượng này ta có thể tham khảo trong Documentation. Hàm getJSON của jQuery cần 3 tham số. Thứ nhất đó là đường dẫn đến dịch vụ API, ở đây tôi đã lưu nó vào biến url nên giờ chỉ cần truyền biến url vào. Tham số thứ hai là đối tượng chứa các thông số kèm theo request, ở đây tôi truyền vào biến reqParams. Cuối cùng, tham số thứ ba là tên hàm sẽ gọi chạy khi nhận được response trả về từ phía server. Phần này không có gì phức tạp, nếu bạn quen dùng tính năng Ajax của jQuery thì đoạn code trên chỉ là chuyện nhỏ.
Tiếp theo ta sẽ viết một hàm callBack() để nó sẽ chạy tự động khi nhận được response từ server.
Hàm callBack() có 2 tham số. Tham số data chứa dữ liệu trả về từ server. Còn tham số status chứa trạng thái của request. Nếu có lỗi gì xảy ra, ta sẽ được thông báo trong biến status này. Trong phần thân hàm, tôi tiến hành mổ xẻ nội dung của biến data. Để xem nội dung biến này, ta có thể dùng câu lệnh console.log(data) để hiển thị nội dung của nó trong cửa sổ console. Thao tác này chắc bạn đã rành nên tôi không đi vào chi tiết. Dựa vào những nội dung khám phá ra trong cửa sổ console, tôi biết được những dữ liệu cần lấy ra nằm ở vị trí nào, và trong phần thân hàm callBack(), tôi lần lượt lấy nó ra và đưa vào biến thích hợp mà tôi đã khai báo ngay từ đầu. Ở dòng 2, tôi lưu đối tượng photo vào trong biến photoObj. Kế đến, tôi lần lượt lấy ra thông tin về tổng số hình (total) và tổng số trang (pages) và gán nó vào biến phù hợp. Cuối cùng, tôi gọi hàm listPhotos() có nhiệm vụ hiển thị danh sách các link hình vừa nhận được ra trình duyệt. Tôi truyền vào trong hàm này một mảng chứa các đối tượng hình của Flickr, để sau đó, trong phần thân hàm listPhotos(), tôi sẽ trích ra từng đường link đến tấm hình tương ứng.
Tiếp theo, ta sẽ viết hàm listPhotos() như đã đề cập ở trên. Cụ thể như sau:
Có thể nói, đây là hàm phức tạp nhất trong tất cả các hàm của ứng dụng này. Đầu tiên, tôi sẽ tính coi phải gửi bao nhiêu request đến server. Như đã đề cập ở đầu bài, Flickr chỉ cho phép trả về tối đa 500 hình trong một request, do đó, nếu muốn lấy nhiều hơn 500 hình, ta phải gửi nhiều request. Nếu nhạy bén, ta sẽ phát hiện ra số request cần gửi tương ứng với tổng số trang chứa hình, mỗi trang chứa 500 tấm. Do đó, tôi sẽ gửi request tương ứng với số trang, có bao nhiêu trang thì sẽ có bấy nhiêu request. Tôi kiểm tra điều kiện này trong câu lệnh if ở dòng 2.
Kế đến, tôi tạo ra một vài biến để chứa các thông tin mà tôi cần lấy ra khỏi đống bùi nhùi mà Flickr trả về dưới dạng object. Tiếp theo, tôi dùng vòng lặp for để lặp qua toàn bộ phần tử trong mảng photoArray chứa tất cả hình trong một trang và trích ra đường dẫn trực tiếp đến hình. Lưu ý ở đây tôi dùng thêm một hàm phụ có tên là getLargestSize() để lấy ra kích thước lớn nhất của ảnh. Như tôi đã có đề cập ở trên, không phải tấm hình nào cũng có tất cả các kích thước, do đó, phải sẽ phải dùng hàm phụ getLargestSize() để lấy ra hình có kích cỡ lớn nhất có thể. Tôi lưu đường link trực tiếp tới hình vào biến directLink. Ngay bên dưới, tôi định dạng đường link bằng cách cho nó vào thẻ anchor rồi gán vào trong biến link.
Bên cạnh việc hiển thị link, tôi muốn hiển thị luôn tiêu đề của bức ảnh. Tuy nhiên, không phải tấm hình nào cũng có tiêu đề, nên tôi phải kiểm tra trước. Nếu có thì hiển thị ra, còn không thì thôi như bạn thấy ở dòng 11. Cuối cùng, tôi gom mọi thứ lại và nhét vào trong biến output để lát nữa chèn vào thẻ div có id là result (dòng 16). Và tôi cũng không quên tăng số trang hiện tại lên 1 đơn vị (dòng 17) để lần sau chạy nó sẽ lấy hình ở trang tiếp theo. Trong phần else, nếu trang hiện tại (currentPage) lớn hơn tổng số trang (totalPages), nghĩa là đã lấy xong toàn bộ hình, tôi sẽ bỏ interval đi (tôi sẽ giải thích cái interval này ở bên dưới). Sau đó tôi đưa thông báo ra màn hình ở dòng 20.
Hàm tiếp theo mà ta sẽ viết là getLargestSize(). Mục đích của hàm này khá đơn giản, đó là tìm ra kích thước hình lớn nhất và trả về đường link tới nó. Nếu không tìm được thì nó sẽ tìm tiếp đường link tới kích thước lớn tiếp theo và cứ như thế cho đến kích thước cuối cùng.
Hàm getLargestSize() chỉ bao gồm các câu lệnh if để kiểm tra điều kiện rồi trả về kết quả sau cùng. Tiếp theo, ta sẽ viết hàm run() dùng làm điểm khởi đầu để chạy toàn bộ quy trình lấy hình.
Đầu tiên, ta lấy giá trị nhập vào của người dùng. Ở đây, giá trị chính là mã số ID của tài khoản người dùng Flickr. Sau đó, tôi gọi chạy hàm getUserPhotos() để tiến hành gửi request đến Flickr. Vậy là phần khó khăn nhất đã hoàn thành, giờ ta còn phải làm một bước cuối cùng đó là tạo một hàm xử lý sự kiện click cho nút bấm có id là get.
Nội dung của hàm này khá rõ rồi nên tôi không cần phải giải thích gì thêm. Tuy nhiên, có một điểm nho nhỏ mà tôi muốn đề cập là vấn đề dùng setInterval() để chạy request sau mỗi 3 giây. Lý do chính mà tôi làm việc này là để tránh tình trạng lạm dụng (abuse) server của Flickr, khiến nó khóa tài khoản của tôi. Đây cũng là điều mà ta nên suy xét thật kỹ khi sử dụng bất kỳ dịch vụ API nào. Gửi request quá nhiều lần trong một khoảng thời gian ngắn là điều cấm kị, và nhà cung cấp API sẽ không vui khi ta làm điều đó. Cho nên tốt nhất là ta kéo dài khoảng cách thời gian gửi request, hoặc cũng có thể cho chạy random để giả lập hành vi người dùng, tránh mọi nghi ngờ từ phía nhà cung cấp API. Bạn cũng đừng quên coi kỹ các chính sách và yêu cầu của nó khi sử dụng dịch vụ. Tốt nhất là ta nên “chấp hành nghiêm chỉnh đường lối” của Flickr để tránh tai họa về sau.
Vậy là ứng dụng chôm hình từ tài khoản Flickr đã xong, ta có thể chia sẻ ứng dụng này cho người khác dùng. Tuy nhiên, cần lưu ý một điều là cái API Key được lưu trong file JavaScript và nó có thể được truy cập bởi bất kỳ ai. Do đó, tôi khuyên bạn không nên công khai cái ứng dụng này trên mạng, tránh trường hợp bị kẻ gian lợi dụng cái API Key và hậu quả là Flickr khóa tài khoản của bạn. Ông anh họ của tôi khá hài lòng với cái ứng dụng này. Trong máy ổng có cài Internet Download Manager, chỉ cần click phải chuột và chọn Download all links with IDM là có thể tải về toàn bộ ảnh từ tài khoản Flickr của bất kỳ ai. Ổng khen phương pháp này nhanh, hiệu quả mà không phức tạp, rất phù hợp cho những người mù tin học như ổng. Kết quả là tôi được một chầu cà phê miễn phí. Đời developer thật là sang!
Nguồn: Blog hieusensei

No comments:

Post a Comment